@ieeesa-npm/dashboard 0.0.0-stage → 0.0.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.
- package/README.md +75 -3
- package/esm2022/ieeesa-npm-dashboard.mjs +5 -0
- package/esm2022/lib/assets/constants.json +158 -0
- package/esm2022/lib/assets/dashboard-mock.mjs +221 -0
- package/esm2022/lib/assets/dashboard-route-paths.mock.mjs +14 -0
- package/esm2022/lib/assets/dashboard-user-permissions.mock.mjs +23 -0
- package/esm2022/lib/assets/date-formats.mjs +28 -0
- package/esm2022/lib/components/event-group-card/event-group-card.component.mjs +414 -0
- package/esm2022/lib/components/meeting-attendance-row/meeting-attendance-row.component.mjs +182 -0
- package/esm2022/lib/components/member-level-badge/member-level-badge.component.mjs +79 -0
- package/esm2022/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.mjs +261 -0
- package/esm2022/lib/components/welcome-header/dashboard-welcome-header.component.mjs +151 -0
- package/esm2022/lib/components/your-groups/your-groups.component.mjs +243 -0
- package/esm2022/lib/dashboard.component.mjs +417 -0
- package/esm2022/lib/dashboard.module.mjs +16 -0
- package/esm2022/lib/dashboard.routes.mjs +7 -0
- package/esm2022/lib/models/attendance-action-permissions.model.mjs +2 -0
- package/esm2022/lib/models/attendance-state.model.mjs +7 -0
- package/esm2022/lib/models/dashboard-list-response.model.mjs +2 -0
- package/esm2022/lib/models/dashboard-route-config.model.mjs +2 -0
- package/esm2022/lib/models/dashboard-section-state.model.mjs +9 -0
- package/esm2022/lib/models/dashboard-user-info.model.mjs +2 -0
- 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 +2 -0
- package/esm2022/lib/models/meeting-row.model.mjs +2 -0
- package/esm2022/lib/models/my-groups-view.model.mjs +2 -0
- package/esm2022/lib/models/page-change.model.mjs +2 -0
- package/esm2022/lib/models/upcoming-event.model.mjs +13 -0
- package/esm2022/lib/services/attendance-reducers.mjs +54 -0
- package/esm2022/lib/services/dashboard.service.mjs +402 -0
- package/esm2022/lib/services/user-permissions.service.mjs +50 -0
- package/esm2022/lib/utils/attendance-action.util.mjs +53 -0
- 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 +36 -0
- package/fesm2022/ieeesa-npm-dashboard.mjs +2981 -0
- package/fesm2022/ieeesa-npm-dashboard.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/assets/dashboard-mock.d.ts +31 -0
- package/lib/assets/dashboard-route-paths.mock.d.ts +2 -0
- package/lib/assets/dashboard-user-permissions.mock.d.ts +2 -0
- package/lib/assets/date-formats.d.ts +27 -0
- package/lib/components/event-group-card/event-group-card.component.d.ts +268 -0
- package/lib/components/meeting-attendance-row/meeting-attendance-row.component.d.ts +115 -0
- package/lib/components/member-level-badge/member-level-badge.component.d.ts +177 -0
- package/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.d.ts +175 -0
- package/lib/components/welcome-header/dashboard-welcome-header.component.d.ts +98 -0
- package/lib/components/your-groups/your-groups.component.d.ts +159 -0
- package/lib/dashboard.component.d.ts +414 -0
- package/lib/dashboard.module.d.ts +7 -0
- package/lib/dashboard.routes.d.ts +2 -0
- package/lib/models/attendance-action-permissions.model.d.ts +4 -0
- package/lib/models/attendance-state.model.d.ts +4 -0
- package/lib/models/dashboard-list-response.model.d.ts +5 -0
- package/lib/models/dashboard-route-config.model.d.ts +7 -0
- package/lib/models/dashboard-section-state.model.d.ts +6 -0
- package/lib/models/dashboard-user-info.model.d.ts +5 -0
- 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 +33 -0
- package/lib/models/meeting-row.model.d.ts +28 -0
- package/lib/models/my-groups-view.model.d.ts +56 -0
- package/lib/models/page-change.model.d.ts +4 -0
- package/lib/models/upcoming-event.model.d.ts +51 -0
- package/lib/services/attendance-reducers.d.ts +43 -0
- package/lib/services/dashboard.service.d.ts +202 -0
- package/lib/services/user-permissions.service.d.ts +31 -0
- package/lib/utils/attendance-action.util.d.ts +38 -0
- package/lib/utils/date-format.util.d.ts +60 -0
- package/lib/utils/event-meeting-mapper.util.d.ts +50 -0
- package/package.json +30 -3
- package/public-api.d.ts +26 -0
|
@@ -0,0 +1,2981 @@
|
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { EventEmitter, Component, ViewEncapsulation, Input, Output, Injectable, ElementRef, ViewChild, NgModule } from '@angular/core';
|
|
5
|
+
import { BehaviorSubject, map, catchError, of, Subject, takeUntil } from 'rxjs';
|
|
6
|
+
import { AlertType } from '@ieeesa-npm/models';
|
|
7
|
+
import * as i1$1 from '@ieeesa-npm/utility';
|
|
8
|
+
import { AlertsService } from '@ieeesa-npm/utility';
|
|
9
|
+
import * as i2 from '@angular/material/paginator';
|
|
10
|
+
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
11
|
+
import * as i3 from '@ieeesa-npm/presentation';
|
|
12
|
+
import { LoaderComponent, LegendComponent } from '@ieeesa-npm/presentation';
|
|
13
|
+
import { DateTime } from 'luxon';
|
|
14
|
+
|
|
15
|
+
/* eslint-disable no-unused-vars */
|
|
16
|
+
var DashboardSectionState;
|
|
17
|
+
(function (DashboardSectionState) {
|
|
18
|
+
DashboardSectionState["LOADING"] = "LOADING";
|
|
19
|
+
DashboardSectionState["LOADED"] = "LOADED";
|
|
20
|
+
DashboardSectionState["EMPTY"] = "EMPTY";
|
|
21
|
+
DashboardSectionState["ERROR"] = "ERROR";
|
|
22
|
+
})(DashboardSectionState || (DashboardSectionState = {}));
|
|
23
|
+
|
|
24
|
+
/* eslint-disable no-unused-vars */
|
|
25
|
+
var AttendanceState;
|
|
26
|
+
(function (AttendanceState) {
|
|
27
|
+
AttendanceState["CURRENTLY_ATTENDING"] = "CURRENTLY_ATTENDING";
|
|
28
|
+
AttendanceState["NOT_ATTENDING"] = "NOT_ATTENDING";
|
|
29
|
+
})(AttendanceState || (AttendanceState = {}));
|
|
30
|
+
|
|
31
|
+
/* eslint-disable no-unused-vars */
|
|
32
|
+
/**
|
|
33
|
+
* Discriminates how a row in the "Upcoming Meetings & Events" list is rendered.
|
|
34
|
+
* EVENT rows render as an expandable event block that owns child meetings;
|
|
35
|
+
* STANDALONE_MEETING rows render as a single meeting card and always sort LAST
|
|
36
|
+
* within the list.
|
|
37
|
+
*/
|
|
38
|
+
var UpcomingItemKind;
|
|
39
|
+
(function (UpcomingItemKind) {
|
|
40
|
+
UpcomingItemKind["EVENT"] = "EVENT";
|
|
41
|
+
UpcomingItemKind["STANDALONE_MEETING"] = "STANDALONE_MEETING";
|
|
42
|
+
})(UpcomingItemKind || (UpcomingItemKind = {}));
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Luxon format tokens used across the dashboard library for rendering
|
|
46
|
+
* event/meeting dates, times, and timezones.
|
|
47
|
+
*
|
|
48
|
+
* These tokens follow the luxon `DateTime.toFormat()` convention
|
|
49
|
+
* (NOT moment). New code in this library must use luxon exclusively.
|
|
50
|
+
*
|
|
51
|
+
* @see https://moment.github.io/luxon/#/formatting?id=table-of-tokens
|
|
52
|
+
*/
|
|
53
|
+
const DateFormats = {
|
|
54
|
+
/** ISO date used for request payloads, e.g. 2025-03-14. */
|
|
55
|
+
requestPayloadFormat: 'yyyy-MM-dd',
|
|
56
|
+
/** ISO date-time used for request payloads, e.g. 2025-03-14T09:30:00. */
|
|
57
|
+
requestPayloadDateTimeFormat: "yyyy-MM-dd'T'HH:mm:ss",
|
|
58
|
+
/** Human-readable date for display, e.g. 14 Mar 2025. */
|
|
59
|
+
displayFormat: 'dd MMM yyyy',
|
|
60
|
+
/** Human-readable long date for display, e.g. 14 March 2025. */
|
|
61
|
+
displayLongFormat: 'dd MMMM yyyy',
|
|
62
|
+
/** 24-hour time for display, e.g. 09:30. */
|
|
63
|
+
timeFormat: 'HH:mm',
|
|
64
|
+
/** 12-hour time with meridiem for display, e.g. 9:30 AM. */
|
|
65
|
+
timeMeridiemFormat: 'h:mm a',
|
|
66
|
+
/** Short timezone abbreviation for display, e.g. EST. */
|
|
67
|
+
timezoneFormat: 'ZZZZ',
|
|
68
|
+
/** Long timezone name for display, e.g. Eastern Standard Time. */
|
|
69
|
+
timezoneLongFormat: 'ZZZZZ',
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Pure helpers for the per-meeting attendance action state machine. No Angular /
|
|
74
|
+
* service dependencies so they are trivially testable (property-tested as
|
|
75
|
+
* Property 1) and reusable by `MeetingAttendanceRowComponent`.
|
|
76
|
+
*
|
|
77
|
+
* The handler is the single source of truth for what a meeting row's action
|
|
78
|
+
* button should emit when activated. The displayed `AttendanceState` only
|
|
79
|
+
* advances on a successful resolution (handled by the service reducers), so this
|
|
80
|
+
* function is a pure mapping from the current inputs to the action to emit.
|
|
81
|
+
*/
|
|
82
|
+
/* eslint-disable no-unused-vars */
|
|
83
|
+
/**
|
|
84
|
+
* The action a meeting row's action button should emit when activated.
|
|
85
|
+
* `NONE` means the activation is non-actionable (empty id or in-flight) and the
|
|
86
|
+
* row must emit no `logAttendance` / `leaveMeeting` / navigation event.
|
|
87
|
+
*/
|
|
88
|
+
var AttendanceAction;
|
|
89
|
+
(function (AttendanceAction) {
|
|
90
|
+
AttendanceAction["LOG_ATTENDANCE"] = "LOG_ATTENDANCE";
|
|
91
|
+
AttendanceAction["LEAVE_MEETING"] = "LEAVE_MEETING";
|
|
92
|
+
AttendanceAction["NONE"] = "NONE";
|
|
93
|
+
})(AttendanceAction || (AttendanceAction = {}));
|
|
94
|
+
/* eslint-enable no-unused-vars */
|
|
95
|
+
/**
|
|
96
|
+
* Resolves the attendance action to emit for a meeting row, following the
|
|
97
|
+
* attendance action state machine (see design: Attendance Action State Machine).
|
|
98
|
+
*
|
|
99
|
+
* Behavior:
|
|
100
|
+
* - Returns `NONE` when `meetingId` is empty or undefined (non-actionable row).
|
|
101
|
+
* - Returns `NONE` while the row is in-flight (re-entrancy guard — no further
|
|
102
|
+
* event is emitted until the current action resolves).
|
|
103
|
+
* - Returns `LEAVE_MEETING` when the state is `CURRENTLY_ATTENDING`.
|
|
104
|
+
* - Returns `LOG_ATTENDANCE` when the state is `NOT_ATTENDING` or undefined.
|
|
105
|
+
*
|
|
106
|
+
* @param {AttendanceState | undefined} attendanceState The row's current attendance state.
|
|
107
|
+
* @param {boolean} isInFlight Whether an attendance action for this row is awaiting resolution.
|
|
108
|
+
* @param {string | undefined} meetingId The row's meeting identifier.
|
|
109
|
+
* @return {AttendanceAction} The action to emit, or `NONE` when non-actionable.
|
|
110
|
+
*/
|
|
111
|
+
function resolveAttendanceAction(attendanceState, isInFlight, meetingId) {
|
|
112
|
+
if (!meetingId) {
|
|
113
|
+
return AttendanceAction.NONE;
|
|
114
|
+
}
|
|
115
|
+
if (isInFlight) {
|
|
116
|
+
return AttendanceAction.NONE;
|
|
117
|
+
}
|
|
118
|
+
if (attendanceState === AttendanceState.CURRENTLY_ATTENDING) {
|
|
119
|
+
return AttendanceAction.LEAVE_MEETING;
|
|
120
|
+
}
|
|
121
|
+
return AttendanceAction.LOG_ATTENDANCE;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Pure luxon date/time formatting helpers for the dashboard library.
|
|
126
|
+
*
|
|
127
|
+
* The real "events & meetings" backend returns date-times as ISO-8601 strings
|
|
128
|
+
* (e.g. "2026-01-01T00:00:00") together with a display timezone string
|
|
129
|
+
* (e.g. "(UTC-04:00) America/New_York"). These helpers parse the ISO value and
|
|
130
|
+
* render it in the item's own zone (never moment). A numeric epoch-milliseconds
|
|
131
|
+
* value is also accepted for backward compatibility with fixtures/tests. All
|
|
132
|
+
* helpers fall back gracefully to an empty string when the value is missing or
|
|
133
|
+
* unparseable.
|
|
134
|
+
*/
|
|
135
|
+
/**
|
|
136
|
+
* Extracts a luxon-usable IANA zone from a backend timezone string such as
|
|
137
|
+
* "(UTC-04:00) America/New_York" or "America/New_York". Returns `undefined`
|
|
138
|
+
* when no usable zone can be derived so luxon falls back to the local zone.
|
|
139
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
140
|
+
* @return {string | undefined} The IANA zone id, or undefined.
|
|
141
|
+
*/
|
|
142
|
+
function extractIanaZone(timezone) {
|
|
143
|
+
if (!timezone) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
// Strip a leading "(UTC±HH:MM) " offset prefix when present.
|
|
147
|
+
const closingParen = timezone.indexOf(') ');
|
|
148
|
+
const zone = closingParen > -1
|
|
149
|
+
? timezone.slice(closingParen + 2).trim()
|
|
150
|
+
: timezone.trim();
|
|
151
|
+
return zone.length > 0 ? zone : undefined;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Parses a backend date-time value — either an ISO-8601 string
|
|
155
|
+
* (e.g. "2026-01-01T00:00:00") or an epoch-milliseconds number — into a luxon
|
|
156
|
+
* {@link DateTime} in the supplied timezone. The ISO value is treated as a wall
|
|
157
|
+
* time in the item's zone so the rendered time matches the backend's intent.
|
|
158
|
+
* Returns an invalid DateTime when the value is missing/unparseable.
|
|
159
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
160
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
161
|
+
* @return {DateTime} The parsed luxon DateTime (may be invalid).
|
|
162
|
+
*/
|
|
163
|
+
function parseBackendDateTime(value, timezone) {
|
|
164
|
+
const zone = extractIanaZone(timezone);
|
|
165
|
+
if (value === undefined || value === null || value === '') {
|
|
166
|
+
return DateTime.invalid('empty');
|
|
167
|
+
}
|
|
168
|
+
if (typeof value === 'number') {
|
|
169
|
+
return zone
|
|
170
|
+
? DateTime.fromMillis(value, { zone })
|
|
171
|
+
: DateTime.fromMillis(value);
|
|
172
|
+
}
|
|
173
|
+
// ISO string: parse as a wall time in the item's zone when known.
|
|
174
|
+
const isoOptions = zone ? { zone } : {};
|
|
175
|
+
const parsed = DateTime.fromISO(value, isoOptions);
|
|
176
|
+
return parsed.isValid ? parsed : DateTime.fromISO(value);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Formats a backend date-time value (ISO string or epoch ms) with luxon using
|
|
180
|
+
* the supplied format token, honouring the supplied timezone. Returns an empty
|
|
181
|
+
* string when the value is missing or invalid.
|
|
182
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
183
|
+
* @param {string} format - The luxon `toFormat` token.
|
|
184
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
185
|
+
* @return {string} The formatted value, or an empty string.
|
|
186
|
+
*/
|
|
187
|
+
function formatBackendDateTime(value, format, timezone) {
|
|
188
|
+
const parsed = parseBackendDateTime(value, timezone);
|
|
189
|
+
return parsed.isValid ? parsed.toFormat(format) : '';
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Backward-compatible alias kept for existing callers. Accepts ISO strings or
|
|
193
|
+
* epoch ms and formats them in the item's zone.
|
|
194
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
195
|
+
* @param {string} format - The luxon `toFormat` token.
|
|
196
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
197
|
+
* @return {string} The formatted value, or an empty string.
|
|
198
|
+
*/
|
|
199
|
+
function formatEpoch(value, format, timezone) {
|
|
200
|
+
return formatBackendDateTime(value, format, timezone);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Computes a human "Day X of Y" indicator for a multi-day event from its start
|
|
204
|
+
* and end date-times, relative to "now". Returns an empty string when the dates
|
|
205
|
+
* are missing/invalid or the event spans a single day.
|
|
206
|
+
* @param {string | number | undefined | null} start - Event start (ISO or epoch ms).
|
|
207
|
+
* @param {string | number | undefined | null} end - Event end (ISO or epoch ms).
|
|
208
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
209
|
+
* @return {string} The "Day X of Y" label, or an empty string.
|
|
210
|
+
*/
|
|
211
|
+
function computeDayIndicator(start, end, timezone) {
|
|
212
|
+
const zone = extractIanaZone(timezone);
|
|
213
|
+
const startDt = parseBackendDateTime(start, timezone);
|
|
214
|
+
const endDt = parseBackendDateTime(end, timezone);
|
|
215
|
+
if (!startDt.isValid || !endDt.isValid) {
|
|
216
|
+
return '';
|
|
217
|
+
}
|
|
218
|
+
const startDay = startDt.startOf('day');
|
|
219
|
+
const endDay = endDt.startOf('day');
|
|
220
|
+
const totalDays = Math.floor(endDay.diff(startDay, 'days').days) + 1;
|
|
221
|
+
// Only meaningful for short, multi-day events (a conference-week style span).
|
|
222
|
+
// Very long spans (e.g. a year-long series) are not shown as "Day X of Y".
|
|
223
|
+
const MAX_DAY_INDICATOR_SPAN = 31;
|
|
224
|
+
if (totalDays <= 1 || totalDays > MAX_DAY_INDICATOR_SPAN) {
|
|
225
|
+
return '';
|
|
226
|
+
}
|
|
227
|
+
const now = (zone ? DateTime.now().setZone(zone) : DateTime.now()).startOf('day');
|
|
228
|
+
const clampedNow = now < startDay ? startDay : now > endDay ? endDay : now;
|
|
229
|
+
const currentDay = Math.floor(clampedNow.diff(startDay, 'days').days) + 1;
|
|
230
|
+
return `Day ${currentDay} of ${totalDays}`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
var welcomeHeader = {
|
|
234
|
+
greeting: "Welcome back, ",
|
|
235
|
+
fallbackGreeting: "Welcome back",
|
|
236
|
+
helperText: "Here's what's happening inside the portal",
|
|
237
|
+
jumpToLabel: "JUMP TO",
|
|
238
|
+
shortcuts: {
|
|
239
|
+
meetings: {
|
|
240
|
+
label: "Upcoming Meetings & Events",
|
|
241
|
+
iconUrl: "/assets/images/icons/attendance-flag.svg",
|
|
242
|
+
ariaLabel: "Jump to upcoming meetings and events"
|
|
243
|
+
},
|
|
244
|
+
groups: {
|
|
245
|
+
label: "Your Groups",
|
|
246
|
+
iconUrl: "/assets/images/icons/icon-committees.svg",
|
|
247
|
+
ariaLabel: "Jump to your groups"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
var upcomingSection = {
|
|
252
|
+
title: "Upcoming Meetings & Events",
|
|
253
|
+
viewAllLabel: "View All",
|
|
254
|
+
expandLabel: "Expand",
|
|
255
|
+
collapseLabel: "Collapse",
|
|
256
|
+
ariaLabel: {
|
|
257
|
+
viewAll: "View all upcoming meetings and events",
|
|
258
|
+
toggle: "Collapse or expand upcoming meetings and events"
|
|
259
|
+
},
|
|
260
|
+
emptyMessage: "You have no upcoming meetings or events.",
|
|
261
|
+
errorMessage: "Unable to load upcoming meetings and events. Please try again.",
|
|
262
|
+
paginator: {
|
|
263
|
+
rangeTemplate: "{start}-{end} of {total} Meetings & Events"
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
var eventGroupCard = {
|
|
267
|
+
eventBadge: "EVENT",
|
|
268
|
+
standaloneBadge: "STANDALONE MEETING",
|
|
269
|
+
viewLabel: "View",
|
|
270
|
+
viewEventLabel: "View Event",
|
|
271
|
+
eventDatesLabel: "EVENT DATES & TIMEZONE",
|
|
272
|
+
meetingDateLabel: "MEETING DATE",
|
|
273
|
+
timeTimezoneLabel: "TIME & TIMEZONE",
|
|
274
|
+
meetingsLabel: "Meetings",
|
|
275
|
+
openForAttendanceTemplate: "{count} Meetings open for attendance",
|
|
276
|
+
meetingListToggle: {
|
|
277
|
+
showLabel: "Show meetings",
|
|
278
|
+
showLabelPrefix: "Show Meetings (",
|
|
279
|
+
showLabelSuffix: " open for attendance)",
|
|
280
|
+
hideLabel: "Hide meetings"
|
|
281
|
+
},
|
|
282
|
+
ariaLabel: {
|
|
283
|
+
view: "View details",
|
|
284
|
+
viewEvent: "View event details",
|
|
285
|
+
meetingListToggle: "Show or hide the meeting list for this event"
|
|
286
|
+
},
|
|
287
|
+
paginator: {
|
|
288
|
+
rangeTemplate: "{start}-{end} of {total} meetings",
|
|
289
|
+
totalTemplate: "{total} meetings scheduled across the event"
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var meetingRow = {
|
|
293
|
+
emptyFieldPlaceholder: "—",
|
|
294
|
+
timeTimezoneLabel: "TIME & TIMEZONE",
|
|
295
|
+
viewLabel: "View",
|
|
296
|
+
currentlyAttendingIndicator: "Currently Attending",
|
|
297
|
+
logAttendanceLabel: "Log Attendance",
|
|
298
|
+
leaveMeetingLabel: "Leave Meeting",
|
|
299
|
+
ariaLabel: {
|
|
300
|
+
meetingNameLink: "View meeting details",
|
|
301
|
+
logAttendance: "Log attendance for this meeting",
|
|
302
|
+
leaveMeeting: "Leave this meeting"
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
var groupsSection = {
|
|
306
|
+
title: "Your Groups",
|
|
307
|
+
viewAllLabel: "View All",
|
|
308
|
+
expandLabel: "Expand",
|
|
309
|
+
collapseLabel: "Collapse",
|
|
310
|
+
countSuffix: "Groups",
|
|
311
|
+
emptyValue: "-",
|
|
312
|
+
unassignedMemberLevel: "Unassigned",
|
|
313
|
+
itemsPerPageLabel: "Items per page",
|
|
314
|
+
ariaLabel: {
|
|
315
|
+
viewAll: "View all your groups",
|
|
316
|
+
toggle: "Collapse or expand your groups",
|
|
317
|
+
groupLink: "View group details"
|
|
318
|
+
},
|
|
319
|
+
columns: {
|
|
320
|
+
group: "Group",
|
|
321
|
+
type: "Type",
|
|
322
|
+
officerRole: "Officer Role",
|
|
323
|
+
affiliation: "Affiliation",
|
|
324
|
+
memberLevel: "Member Level"
|
|
325
|
+
},
|
|
326
|
+
paginator: {
|
|
327
|
+
rangeTemplate: "Showing {start}-{end} of {total}",
|
|
328
|
+
totalTemplate: "{total} groups"
|
|
329
|
+
},
|
|
330
|
+
memberLevelBadge: {
|
|
331
|
+
success: "ieeesa-your-groups__badge--success",
|
|
332
|
+
warning: "ieeesa-your-groups__badge--warning"
|
|
333
|
+
},
|
|
334
|
+
emptyMessage: "You are not a member of any groups.",
|
|
335
|
+
errorMessage: "Unable to load your groups. Please try again."
|
|
336
|
+
};
|
|
337
|
+
var memberLevel = {
|
|
338
|
+
colorMap: {
|
|
339
|
+
"Voting Member": "$ieeesa-color-success",
|
|
340
|
+
Observer: "$ieeesa-color-info",
|
|
341
|
+
"Associate Member": "$ieeesa-color-warning",
|
|
342
|
+
Member: "$ieeesa-color-primary",
|
|
343
|
+
"default": "$ieeesa-color-neutral"
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
var attendance = {
|
|
347
|
+
errorMessage: "Unable to update your attendance. Please try again."
|
|
348
|
+
};
|
|
349
|
+
var footer = {
|
|
350
|
+
links: [
|
|
351
|
+
{
|
|
352
|
+
label: "Dashboard",
|
|
353
|
+
target: "/dashboard"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
label: "Contact & Support",
|
|
357
|
+
target: "https://supportcenter.ieee.org/app/home"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
label: "Accessibility",
|
|
361
|
+
target: "https://www.ieee.org/accessibility-statement.html"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
label: "Nondiscrimination Policy",
|
|
365
|
+
target: "https://www.ieee.org/about/corporate/governance/p9-26.html"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
label: "IEEE Ethics Reporting",
|
|
369
|
+
target: "https://www.ieee.org/about/ethics/index.html"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
label: "IEEE Privacy Policy",
|
|
373
|
+
target: "https://www.ieee.org/security-privacy.html"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
label: "IEEE SA Copyright Policy",
|
|
377
|
+
target: "https://standards.ieee.org/about/policies/"
|
|
378
|
+
}
|
|
379
|
+
],
|
|
380
|
+
copyright: "© Copyright 2024 IEEE - All rights reserved. Use of this website signifies your agreement to the IEEE Terms and Conditions."
|
|
381
|
+
};
|
|
382
|
+
var defaultRouteConfig = {
|
|
383
|
+
eventDetail: "/events",
|
|
384
|
+
meetingDetail: "/meetings",
|
|
385
|
+
groupDetail: "/groups",
|
|
386
|
+
viewAllEvents: "/events-and-meetings/view-events-meetings-list",
|
|
387
|
+
viewAllGroups: "/groups"
|
|
388
|
+
};
|
|
389
|
+
var constants = {
|
|
390
|
+
welcomeHeader: welcomeHeader,
|
|
391
|
+
upcomingSection: upcomingSection,
|
|
392
|
+
eventGroupCard: eventGroupCard,
|
|
393
|
+
meetingRow: meetingRow,
|
|
394
|
+
groupsSection: groupsSection,
|
|
395
|
+
memberLevel: memberLevel,
|
|
396
|
+
attendance: attendance,
|
|
397
|
+
footer: footer,
|
|
398
|
+
defaultRouteConfig: defaultRouteConfig
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
var constants$1 = /*#__PURE__*/Object.freeze({
|
|
402
|
+
__proto__: null,
|
|
403
|
+
attendance: attendance,
|
|
404
|
+
default: constants,
|
|
405
|
+
defaultRouteConfig: defaultRouteConfig,
|
|
406
|
+
eventGroupCard: eventGroupCard,
|
|
407
|
+
footer: footer,
|
|
408
|
+
groupsSection: groupsSection,
|
|
409
|
+
meetingRow: meetingRow,
|
|
410
|
+
memberLevel: memberLevel,
|
|
411
|
+
upcomingSection: upcomingSection,
|
|
412
|
+
welcomeHeader: welcomeHeader
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Meeting_Attendance_Row renders a single meeting within an event-group card:
|
|
417
|
+
* the meeting-name link, group/committee, room/location, date, and
|
|
418
|
+
* time+timezone (all luxon-formatted), together with the attendance action
|
|
419
|
+
* button that drives the per-meeting attendance state machine.
|
|
420
|
+
*
|
|
421
|
+
* The component is purely presentational — it emits navigation and attendance
|
|
422
|
+
* intents via `@Output()` and never performs navigation or HTTP itself. The
|
|
423
|
+
* action button delegates to the pure `resolveAttendanceAction` handler so the
|
|
424
|
+
* emit/guard logic is shared with the property-tested core (Property 1), and the
|
|
425
|
+
* displayed state only advances when the host updates `attendanceState`.
|
|
426
|
+
* @export
|
|
427
|
+
* @class MeetingAttendanceRowComponent
|
|
428
|
+
*/
|
|
429
|
+
class MeetingAttendanceRowComponent {
|
|
430
|
+
constructor() {
|
|
431
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
432
|
+
this.constants = constants$1;
|
|
433
|
+
/** The current attendance state controlling label/indicator and action. */
|
|
434
|
+
this.attendanceState = AttendanceState.NOT_ATTENDING;
|
|
435
|
+
/** Whether an attendance action for this meeting is awaiting resolution. */
|
|
436
|
+
this.isInFlight = false;
|
|
437
|
+
/** Host permissions gating the log-attendance / leave-meeting buttons. */
|
|
438
|
+
this.permissions = {
|
|
439
|
+
canLogAttendance: false,
|
|
440
|
+
canLeaveMeeting: false,
|
|
441
|
+
};
|
|
442
|
+
/**
|
|
443
|
+
* Renders the leaner "standalone meeting" variant used by standalone-meeting
|
|
444
|
+
* cards (the group/location and status live on the parent card, so the row
|
|
445
|
+
* only shows the TIME & TIMEZONE block and the attendance + View actions).
|
|
446
|
+
*/
|
|
447
|
+
this.compact = false;
|
|
448
|
+
/** Emits the meeting id when the meeting-name link is activated (Req 7.4). */
|
|
449
|
+
this.openMeeting = new EventEmitter();
|
|
450
|
+
/** Emits the meeting id to request logging attendance (Req 7.7). */
|
|
451
|
+
this.logAttendance = new EventEmitter();
|
|
452
|
+
/** Emits the meeting id to request leaving the meeting (Req 7.8). */
|
|
453
|
+
this.leaveMeeting = new EventEmitter();
|
|
454
|
+
/** Expose the enum to the template for state comparisons. */
|
|
455
|
+
this.AttendanceState = AttendanceState;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Whether this row is actionable — a non-empty `meetingId` is required for the
|
|
459
|
+
* meeting-name link and action button to emit anything (Req 7.10).
|
|
460
|
+
* @return {boolean} True when the row has a usable meeting id.
|
|
461
|
+
* @memberof MeetingAttendanceRowComponent
|
|
462
|
+
*/
|
|
463
|
+
get isActionable() {
|
|
464
|
+
return !!this.meeting?.meetingId;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Whether the row is in the currently-attending state, which shows the
|
|
468
|
+
* currently-attending indicator and the leave-meeting action (Req 7.5).
|
|
469
|
+
* @return {boolean} True when the attendance state is `CURRENTLY_ATTENDING`.
|
|
470
|
+
* @memberof MeetingAttendanceRowComponent
|
|
471
|
+
*/
|
|
472
|
+
get isCurrentlyAttending() {
|
|
473
|
+
return this.attendanceState === AttendanceState.CURRENTLY_ATTENDING;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Whether the log-attendance button should be shown: only when the row is in
|
|
477
|
+
* the log state (not currently attending) and the host grants
|
|
478
|
+
* `canLogAttendance` (Req 7.6, 12.1).
|
|
479
|
+
* @return {boolean} True when the log-attendance button is visible.
|
|
480
|
+
* @memberof MeetingAttendanceRowComponent
|
|
481
|
+
*/
|
|
482
|
+
get showLogAttendanceButton() {
|
|
483
|
+
return !this.isCurrentlyAttending && !!this.permissions?.canLogAttendance;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Whether the leave-meeting button should be shown: only when the row is in
|
|
487
|
+
* the currently-attending state and the host grants `canLeaveMeeting`
|
|
488
|
+
* (Req 7.5, 12.2).
|
|
489
|
+
* @return {boolean} True when the leave-meeting button is visible.
|
|
490
|
+
* @memberof MeetingAttendanceRowComponent
|
|
491
|
+
*/
|
|
492
|
+
get showLeaveMeetingButton() {
|
|
493
|
+
return this.isCurrentlyAttending && !!this.permissions?.canLeaveMeeting;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Resolves a group-or-committee / room-or-location field value, substituting
|
|
497
|
+
* the empty-field placeholder from `constants.json` when the value is empty or
|
|
498
|
+
* undefined (Req 7.2).
|
|
499
|
+
* @param {string | undefined} value - The raw field value from the meeting.
|
|
500
|
+
* @return {string} The value to display, or the empty-field placeholder.
|
|
501
|
+
* @memberof MeetingAttendanceRowComponent
|
|
502
|
+
*/
|
|
503
|
+
resolveFieldValue(value) {
|
|
504
|
+
const placeholder = this.constants?.meetingRow?.emptyFieldPlaceholder ?? '—';
|
|
505
|
+
return value && value.trim().length > 0 ? value : placeholder;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Formats the meeting date for display using the shared luxon display format
|
|
509
|
+
* (Req 7.3). Falls back to the raw value when it cannot be parsed.
|
|
510
|
+
* @return {string} The formatted meeting date.
|
|
511
|
+
* @memberof MeetingAttendanceRowComponent
|
|
512
|
+
*/
|
|
513
|
+
get formattedDate() {
|
|
514
|
+
const value = this.meeting?.startDateTime ?? this.meeting?.meetingDate;
|
|
515
|
+
return formatEpoch(value, DateFormats.displayFormat, this.meeting?.timezone);
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Formats the meeting time + timezone for display using luxon (Req 7.3).
|
|
519
|
+
* The timezone abbreviation from the meeting model is appended to the parsed
|
|
520
|
+
* time. Falls back to the raw value when it cannot be parsed.
|
|
521
|
+
* @return {string} The formatted meeting time with timezone.
|
|
522
|
+
* @memberof MeetingAttendanceRowComponent
|
|
523
|
+
*/
|
|
524
|
+
get formattedTime() {
|
|
525
|
+
const timezone = this.meeting?.timezone ?? '';
|
|
526
|
+
const startValue = this.meeting?.startDateTime ?? this.meeting?.meetingTime;
|
|
527
|
+
const start = formatEpoch(startValue, DateFormats.timeMeridiemFormat, timezone);
|
|
528
|
+
const end = formatEpoch(this.meeting?.endDateTime, DateFormats.timeMeridiemFormat, timezone);
|
|
529
|
+
const range = end ? `${start} – ${end}` : start;
|
|
530
|
+
if (!range) {
|
|
531
|
+
return '';
|
|
532
|
+
}
|
|
533
|
+
return timezone ? `${range} ${timezone}` : range;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Handles activation of the attendance action button. Delegates to the pure
|
|
537
|
+
* `resolveAttendanceAction` handler and emits exactly one event based on the
|
|
538
|
+
* resolved action: `logAttendance` for `LOG_ATTENDANCE`, `leaveMeeting` for
|
|
539
|
+
* `LEAVE_MEETING`, and nothing for `NONE` (empty id or in-flight)
|
|
540
|
+
* (Req 7.7, 7.8, 7.9, 7.10, 13.6).
|
|
541
|
+
* @memberof MeetingAttendanceRowComponent
|
|
542
|
+
*/
|
|
543
|
+
onAttendanceAction() {
|
|
544
|
+
const action = resolveAttendanceAction(this.attendanceState, this.isInFlight, this.meeting?.meetingId);
|
|
545
|
+
if (action === AttendanceAction.LOG_ATTENDANCE) {
|
|
546
|
+
this.logAttendance.emit(this.meeting.meetingId);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (action === AttendanceAction.LEAVE_MEETING) {
|
|
550
|
+
this.leaveMeeting.emit(this.meeting.meetingId);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Handles activation of the meeting-name link. Emits the meeting id only when
|
|
555
|
+
* the row is actionable (non-empty meeting id) (Req 7.4, 7.10).
|
|
556
|
+
* @memberof MeetingAttendanceRowComponent
|
|
557
|
+
*/
|
|
558
|
+
onOpenMeeting() {
|
|
559
|
+
if (!this.isActionable) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
this.openMeeting.emit(this.meeting.meetingId);
|
|
563
|
+
}
|
|
564
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MeetingAttendanceRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
565
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MeetingAttendanceRowComponent, isStandalone: true, selector: "ieeesa-meeting-attendance-row", inputs: { meeting: "meeting", attendanceState: "attendanceState", isInFlight: "isInFlight", permissions: "permissions", compact: "compact" }, outputs: { openMeeting: "openMeeting", logAttendance: "logAttendance", leaveMeeting: "leaveMeeting" }, ngImport: i0, template: "<div\r\n class=\"ieeesa-meeting-attendance-row\"\r\n [class.ieeesa-meeting-attendance-row--compact]=\"compact\"\r\n>\r\n <!-- Meeting name + group/location (hidden in the compact standalone variant). -->\r\n <div class=\"ieeesa-meeting-attendance-row__name-col\">\r\n <ng-container *ngIf=\"!compact\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__name-link\"\r\n [disabled]=\"!isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.meetingNameLink\"\r\n (click)=\"onOpenMeeting()\"\r\n >\r\n {{ meeting.meetingName }}\r\n </button>\r\n\r\n <p class=\"ieeesa-meeting-attendance-row__subtitle\">\r\n {{ resolveFieldValue(meeting.groupOrCommittee) }}<ng-container\r\n *ngIf=\"meeting.roomOrLocation\"\r\n > · {{ meeting.roomOrLocation }}</ng-container>\r\n </p>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- MEETING DATE column. -->\r\n <dl class=\"ieeesa-meeting-attendance-row__col ieeesa-meeting-attendance-row__col--date\">\r\n <dt class=\"ieeesa-meeting-attendance-row__col-label\">\r\n {{ constants.eventGroupCard.meetingDateLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__col-value\">\r\n {{ formattedDate }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- TIME & TIMEZONE column. -->\r\n <dl class=\"ieeesa-meeting-attendance-row__col ieeesa-meeting-attendance-row__col--time\">\r\n <dt class=\"ieeesa-meeting-attendance-row__col-label\">\r\n {{ constants.meetingRow.timeTimezoneLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__col-value\">\r\n {{ formattedTime }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- Attendance indicator + actions column. -->\r\n <div class=\"ieeesa-meeting-attendance-row__actions\">\r\n <!-- Currently-attending pill shown only in the attending state. -->\r\n <span\r\n *ngIf=\"isCurrentlyAttending\"\r\n class=\"ieeesa-meeting-attendance-row__attending-pill\"\r\n >\r\n <span class=\"ieeesa-meeting-attendance-row__attending-dot\" aria-hidden=\"true\"></span>\r\n {{ constants.meetingRow.currentlyAttendingIndicator }}\r\n </span>\r\n\r\n <!-- Log-attendance button: shown in the log state with the permission. -->\r\n <button\r\n *ngIf=\"showLogAttendanceButton\"\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__action-button ieeesa-meeting-attendance-row__action-button--log\"\r\n [disabled]=\"isInFlight || !isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.logAttendance\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants.meetingRow.logAttendanceLabel }}\r\n </button>\r\n\r\n <!-- Leave-meeting button: shown in the attending state with the permission. -->\r\n <button\r\n *ngIf=\"showLeaveMeetingButton\"\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__action-button ieeesa-meeting-attendance-row__action-button--leave\"\r\n [disabled]=\"isInFlight || !isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.leaveMeeting\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants.meetingRow.leaveMeetingLabel }}\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-meeting-attendance-row{display:grid;grid-template-columns:minmax(220px,2fr) minmax(120px,1fr) minmax(180px,1.2fr) auto;align-items:center;column-gap:24px;min-height:72px;padding:16px 20px;background-color:#fff;font-family:Calibri Regular}.ieeesa-meeting-attendance-row__name-col{display:flex;flex-direction:column;gap:4px;min-width:0}.ieeesa-meeting-attendance-row__name-link{padding:0;border:0;background:none;text-align:left;text-decoration:underline;font-family:Calibri Bold;font-size:1rem;line-height:20px;color:#00629b;cursor:pointer}.ieeesa-meeting-attendance-row__name-link:disabled{color:#939094;text-decoration:none;cursor:default}.ieeesa-meeting-attendance-row__subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-meeting-attendance-row__col{display:flex;flex-direction:column;gap:4px;margin:0;min-width:0}.ieeesa-meeting-attendance-row__col-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-meeting-attendance-row__col-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-meeting-attendance-row__actions{display:flex;align-items:center;justify-content:flex-end;gap:16px;flex-shrink:0}.ieeesa-meeting-attendance-row__attending-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;white-space:nowrap;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-meeting-attendance-row__attending-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-meeting-attendance-row__action-button{min-width:146px;padding:10px 16px;border-radius:4px;font-family:Calibri Bold;font-size:.875rem;cursor:pointer}.ieeesa-meeting-attendance-row__action-button--log{border:1px solid #00629b;background-color:#00629b;color:#fff}.ieeesa-meeting-attendance-row__action-button--leave{border:1px solid #00629b;background-color:#fff;color:#00629b}.ieeesa-meeting-attendance-row__action-button:disabled{border-color:#939094;background-color:#939094;color:#fff;cursor:default}.ieeesa-meeting-attendance-row:not(.ieeesa-meeting-attendance-row--compact)+.ieeesa-meeting-attendance-row:not(.ieeesa-meeting-attendance-row--compact){border-top:1px solid #d7d6d6}.ieeesa-meeting-attendance-row--compact{grid-template-columns:minmax(180px,1.2fr) auto;padding:0;min-height:0}.ieeesa-meeting-attendance-row--compact .ieeesa-meeting-attendance-row__col--date{display:none}@media (max-width: 767px){.ieeesa-meeting-attendance-row{grid-template-columns:1fr;row-gap:12px}.ieeesa-meeting-attendance-row__actions{justify-content:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
566
|
+
}
|
|
567
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MeetingAttendanceRowComponent, decorators: [{
|
|
568
|
+
type: Component,
|
|
569
|
+
args: [{ selector: 'ieeesa-meeting-attendance-row', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<div\r\n class=\"ieeesa-meeting-attendance-row\"\r\n [class.ieeesa-meeting-attendance-row--compact]=\"compact\"\r\n>\r\n <!-- Meeting name + group/location (hidden in the compact standalone variant). -->\r\n <div class=\"ieeesa-meeting-attendance-row__name-col\">\r\n <ng-container *ngIf=\"!compact\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__name-link\"\r\n [disabled]=\"!isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.meetingNameLink\"\r\n (click)=\"onOpenMeeting()\"\r\n >\r\n {{ meeting.meetingName }}\r\n </button>\r\n\r\n <p class=\"ieeesa-meeting-attendance-row__subtitle\">\r\n {{ resolveFieldValue(meeting.groupOrCommittee) }}<ng-container\r\n *ngIf=\"meeting.roomOrLocation\"\r\n > · {{ meeting.roomOrLocation }}</ng-container>\r\n </p>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- MEETING DATE column. -->\r\n <dl class=\"ieeesa-meeting-attendance-row__col ieeesa-meeting-attendance-row__col--date\">\r\n <dt class=\"ieeesa-meeting-attendance-row__col-label\">\r\n {{ constants.eventGroupCard.meetingDateLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__col-value\">\r\n {{ formattedDate }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- TIME & TIMEZONE column. -->\r\n <dl class=\"ieeesa-meeting-attendance-row__col ieeesa-meeting-attendance-row__col--time\">\r\n <dt class=\"ieeesa-meeting-attendance-row__col-label\">\r\n {{ constants.meetingRow.timeTimezoneLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__col-value\">\r\n {{ formattedTime }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- Attendance indicator + actions column. -->\r\n <div class=\"ieeesa-meeting-attendance-row__actions\">\r\n <!-- Currently-attending pill shown only in the attending state. -->\r\n <span\r\n *ngIf=\"isCurrentlyAttending\"\r\n class=\"ieeesa-meeting-attendance-row__attending-pill\"\r\n >\r\n <span class=\"ieeesa-meeting-attendance-row__attending-dot\" aria-hidden=\"true\"></span>\r\n {{ constants.meetingRow.currentlyAttendingIndicator }}\r\n </span>\r\n\r\n <!-- Log-attendance button: shown in the log state with the permission. -->\r\n <button\r\n *ngIf=\"showLogAttendanceButton\"\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__action-button ieeesa-meeting-attendance-row__action-button--log\"\r\n [disabled]=\"isInFlight || !isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.logAttendance\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants.meetingRow.logAttendanceLabel }}\r\n </button>\r\n\r\n <!-- Leave-meeting button: shown in the attending state with the permission. -->\r\n <button\r\n *ngIf=\"showLeaveMeetingButton\"\r\n type=\"button\"\r\n class=\"ieeesa-meeting-attendance-row__action-button ieeesa-meeting-attendance-row__action-button--leave\"\r\n [disabled]=\"isInFlight || !isActionable\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.leaveMeeting\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants.meetingRow.leaveMeetingLabel }}\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-meeting-attendance-row{display:grid;grid-template-columns:minmax(220px,2fr) minmax(120px,1fr) minmax(180px,1.2fr) auto;align-items:center;column-gap:24px;min-height:72px;padding:16px 20px;background-color:#fff;font-family:Calibri Regular}.ieeesa-meeting-attendance-row__name-col{display:flex;flex-direction:column;gap:4px;min-width:0}.ieeesa-meeting-attendance-row__name-link{padding:0;border:0;background:none;text-align:left;text-decoration:underline;font-family:Calibri Bold;font-size:1rem;line-height:20px;color:#00629b;cursor:pointer}.ieeesa-meeting-attendance-row__name-link:disabled{color:#939094;text-decoration:none;cursor:default}.ieeesa-meeting-attendance-row__subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-meeting-attendance-row__col{display:flex;flex-direction:column;gap:4px;margin:0;min-width:0}.ieeesa-meeting-attendance-row__col-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-meeting-attendance-row__col-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-meeting-attendance-row__actions{display:flex;align-items:center;justify-content:flex-end;gap:16px;flex-shrink:0}.ieeesa-meeting-attendance-row__attending-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;white-space:nowrap;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-meeting-attendance-row__attending-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-meeting-attendance-row__action-button{min-width:146px;padding:10px 16px;border-radius:4px;font-family:Calibri Bold;font-size:.875rem;cursor:pointer}.ieeesa-meeting-attendance-row__action-button--log{border:1px solid #00629b;background-color:#00629b;color:#fff}.ieeesa-meeting-attendance-row__action-button--leave{border:1px solid #00629b;background-color:#fff;color:#00629b}.ieeesa-meeting-attendance-row__action-button:disabled{border-color:#939094;background-color:#939094;color:#fff;cursor:default}.ieeesa-meeting-attendance-row:not(.ieeesa-meeting-attendance-row--compact)+.ieeesa-meeting-attendance-row:not(.ieeesa-meeting-attendance-row--compact){border-top:1px solid #d7d6d6}.ieeesa-meeting-attendance-row--compact{grid-template-columns:minmax(180px,1.2fr) auto;padding:0;min-height:0}.ieeesa-meeting-attendance-row--compact .ieeesa-meeting-attendance-row__col--date{display:none}@media (max-width: 767px){.ieeesa-meeting-attendance-row{grid-template-columns:1fr;row-gap:12px}.ieeesa-meeting-attendance-row__actions{justify-content:flex-start}}\n"] }]
|
|
570
|
+
}], propDecorators: { meeting: [{
|
|
571
|
+
type: Input
|
|
572
|
+
}], attendanceState: [{
|
|
573
|
+
type: Input
|
|
574
|
+
}], isInFlight: [{
|
|
575
|
+
type: Input
|
|
576
|
+
}], permissions: [{
|
|
577
|
+
type: Input
|
|
578
|
+
}], compact: [{
|
|
579
|
+
type: Input
|
|
580
|
+
}], openMeeting: [{
|
|
581
|
+
type: Output
|
|
582
|
+
}], logAttendance: [{
|
|
583
|
+
type: Output
|
|
584
|
+
}], leaveMeeting: [{
|
|
585
|
+
type: Output
|
|
586
|
+
}] } });
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Event_Group_Card renders a single upcoming event as a card: the status badge,
|
|
590
|
+
* title, day indicator, meeting-count summary sub-line, start/end date, and
|
|
591
|
+
* timezone (all luxon-formatted). It exposes a "View Event" action, a
|
|
592
|
+
* show/hide toggle for the meeting list labeled with the open-for-attendance
|
|
593
|
+
* count, the per-event meeting rows (one {@link MeetingAttendanceRowComponent}
|
|
594
|
+
* per meeting on the current page), and a per-card paginator.
|
|
595
|
+
*
|
|
596
|
+
* The component is purely presentational — it emits navigation, attendance, and
|
|
597
|
+
* pagination intents via `@Output()` and never performs navigation or HTTP
|
|
598
|
+
* itself. Meeting-row outputs (`openMeeting`/`logAttendance`/`leaveMeeting`) are
|
|
599
|
+
* bubbled upward unchanged so the container can delegate to the service.
|
|
600
|
+
* @export
|
|
601
|
+
* @class EventGroupCardComponent
|
|
602
|
+
*/
|
|
603
|
+
class EventGroupCardComponent {
|
|
604
|
+
constructor() {
|
|
605
|
+
/** User-facing strings sourced from `constants.json`. */
|
|
606
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
607
|
+
this.constants = constants$1;
|
|
608
|
+
/** Enum reference for EVENT vs STANDALONE_MEETING comparisons in the template. */
|
|
609
|
+
this.itemKinds = UpcomingItemKind;
|
|
610
|
+
/** Host permissions gating the per-row log-attendance / leave-meeting buttons. */
|
|
611
|
+
this.permissions = {
|
|
612
|
+
canLogAttendance: false,
|
|
613
|
+
canLeaveMeeting: false,
|
|
614
|
+
};
|
|
615
|
+
/** Map of meeting id to current attendance state, passed down to each row. */
|
|
616
|
+
this.attendanceStates = {};
|
|
617
|
+
/** Set of meeting ids with an attendance action awaiting resolution. */
|
|
618
|
+
this.inFlightMeetingIds = new Set();
|
|
619
|
+
/** Whether the host has determined the viewport is at/below the mobile breakpoint. */
|
|
620
|
+
this.isMobileView = false;
|
|
621
|
+
/** Emits the event id when the "View Event" button is activated (Req 6.4). */
|
|
622
|
+
this.viewEvent = new EventEmitter();
|
|
623
|
+
/** Bubbles the meeting id when a row's meeting-name link is activated (Req 6.7, 7.4). */
|
|
624
|
+
this.openMeeting = new EventEmitter();
|
|
625
|
+
/** Bubbles the meeting id when a row requests logging attendance (Req 6.7, 7.7). */
|
|
626
|
+
this.logAttendance = new EventEmitter();
|
|
627
|
+
/** Bubbles the meeting id when a row requests leaving the meeting (Req 6.7, 7.8). */
|
|
628
|
+
this.leaveMeeting = new EventEmitter();
|
|
629
|
+
/** Emits the requested page when the per-card paginator changes (Req 6.9, 3.3). */
|
|
630
|
+
this.pageChange = new EventEmitter();
|
|
631
|
+
/**
|
|
632
|
+
* Emits the one-based page to load when the meeting list is opened (or paged)
|
|
633
|
+
* so the container can lazily fetch the event's child meetings from the
|
|
634
|
+
* backend. Standalone-meeting cards never emit this.
|
|
635
|
+
*/
|
|
636
|
+
this.loadMeetings = new EventEmitter();
|
|
637
|
+
/** The default page size for the per-card meeting paginator. */
|
|
638
|
+
this.defaultPageSize = 5;
|
|
639
|
+
/** The current zero-based page index of the meeting list. */
|
|
640
|
+
this.pageIndex = 0;
|
|
641
|
+
/** The current page size of the meeting list. */
|
|
642
|
+
this.pageSize = this.defaultPageSize;
|
|
643
|
+
/** Whether the meeting list is currently shown (toggled open). */
|
|
644
|
+
this.isMeetingListOpen = false;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* The event status slugified into a BEM modifier suffix (lowercase, spaces to
|
|
648
|
+
* hyphens), e.g. "In Progress" -> "in-progress", used to colour the status
|
|
649
|
+
* pill per status.
|
|
650
|
+
* @return {string} The status modifier suffix.
|
|
651
|
+
* @memberof EventGroupCardComponent
|
|
652
|
+
*/
|
|
653
|
+
get statusModifier() {
|
|
654
|
+
return (this.event?.status ?? '')
|
|
655
|
+
.trim()
|
|
656
|
+
.toLowerCase()
|
|
657
|
+
.replace(/\s+/g, '-');
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Whether this card renders a STANDALONE_MEETING (leaner single-meeting card
|
|
661
|
+
* with no child-meeting list) rather than an expandable EVENT block.
|
|
662
|
+
* @return {boolean} True for standalone-meeting cards.
|
|
663
|
+
* @memberof EventGroupCardComponent
|
|
664
|
+
*/
|
|
665
|
+
get isStandalone() {
|
|
666
|
+
return this.event?.kind === UpcomingItemKind.STANDALONE_MEETING;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* The full list of meetings for the event, defaulting to an empty list when
|
|
670
|
+
* the event has none.
|
|
671
|
+
* @return {MeetingRow[]} The event's meetings.
|
|
672
|
+
* @memberof EventGroupCardComponent
|
|
673
|
+
*/
|
|
674
|
+
get meetings() {
|
|
675
|
+
return this.event?.meetings ?? [];
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* The total number of meetings for the event (paginator length). Uses the
|
|
679
|
+
* backend `meetingCount` (the full total) rather than the length of the
|
|
680
|
+
* currently loaded page, so the paginator can advance through every page.
|
|
681
|
+
* @return {number} The total meeting count.
|
|
682
|
+
* @memberof EventGroupCardComponent
|
|
683
|
+
*/
|
|
684
|
+
get totalMeetings() {
|
|
685
|
+
return this.event?.meetingCount || this.meetings.length;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* The meetings to render for the current page. The server returns exactly one
|
|
689
|
+
* page of meetings into `event.meetings`, so the card renders them as-is
|
|
690
|
+
* without local slicing (pagination is server-side).
|
|
691
|
+
* @return {MeetingRow[]} The meetings on the current page.
|
|
692
|
+
* @memberof EventGroupCardComponent
|
|
693
|
+
*/
|
|
694
|
+
get pagedMeetings() {
|
|
695
|
+
return this.meetings;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* The one-based index of the first meeting shown on the current page, or 0
|
|
699
|
+
* when there are no meetings.
|
|
700
|
+
* @return {number} The start index for the range template.
|
|
701
|
+
* @memberof EventGroupCardComponent
|
|
702
|
+
*/
|
|
703
|
+
get rangeStart() {
|
|
704
|
+
return this.totalMeetings === 0 ? 0 : this.pageIndex * this.pageSize + 1;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* The one-based index of the last meeting shown on the current page, clamped
|
|
708
|
+
* to the total meeting count.
|
|
709
|
+
* @return {number} The end index for the range template.
|
|
710
|
+
* @memberof EventGroupCardComponent
|
|
711
|
+
*/
|
|
712
|
+
get rangeEnd() {
|
|
713
|
+
return Math.min((this.pageIndex + 1) * this.pageSize, this.totalMeetings);
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* The paginator range label (e.g. "Showing 1-5 of 12") built from the
|
|
717
|
+
* `constants.json` range template with the current start/end/total values.
|
|
718
|
+
* @return {string} The formatted range label.
|
|
719
|
+
* @memberof EventGroupCardComponent
|
|
720
|
+
*/
|
|
721
|
+
get rangeLabel() {
|
|
722
|
+
const template = this.constants?.eventGroupCard?.paginator?.rangeTemplate ??
|
|
723
|
+
'Showing {start}-{end} of {total}';
|
|
724
|
+
return template
|
|
725
|
+
.replace('{start}', `${this.rangeStart}`)
|
|
726
|
+
.replace('{end}', `${this.rangeEnd}`)
|
|
727
|
+
.replace('{total}', `${this.totalMeetings}`);
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* The meeting-count summary sub-line (e.g. "12 meetings") built from the
|
|
731
|
+
* `constants.json` total template with the event's meeting count.
|
|
732
|
+
* @return {string} The formatted meeting-count summary.
|
|
733
|
+
* @memberof EventGroupCardComponent
|
|
734
|
+
*/
|
|
735
|
+
get meetingCountSummary() {
|
|
736
|
+
const template = this.constants?.eventGroupCard?.paginator?.totalTemplate ??
|
|
737
|
+
'{total} meetings';
|
|
738
|
+
return template.replace('{total}', `${this.event?.meetingCount ?? 0}`);
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* The header sub-line: the group · location line for a STANDALONE meeting, or
|
|
742
|
+
* the "{n} meetings scheduled across the event" summary for an EVENT when its
|
|
743
|
+
* meeting count is known (hidden until the count is loaded so it never shows
|
|
744
|
+
* "0 meetings").
|
|
745
|
+
* @return {string} The sub-line text, or an empty string to hide it.
|
|
746
|
+
* @memberof EventGroupCardComponent
|
|
747
|
+
*/
|
|
748
|
+
get subtitleText() {
|
|
749
|
+
if (this.isStandalone) {
|
|
750
|
+
const group = this.event?.groupOrCommittee ?? '';
|
|
751
|
+
const location = this.event?.roomOrLocation ?? '';
|
|
752
|
+
if (group && location) {
|
|
753
|
+
return `${group} \u00b7 ${location}`;
|
|
754
|
+
}
|
|
755
|
+
return group || location;
|
|
756
|
+
}
|
|
757
|
+
return (this.event?.meetingCount ?? 0) > 0 ? this.meetingCountSummary : '';
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* The meeting-list show/hide toggle label. When the list is hidden the label
|
|
761
|
+
* reads "Show Meetings ({count} open for attendance)" built from the
|
|
762
|
+
* `constants.json` templates and the event's open-for-attendance count; when
|
|
763
|
+
* the list is shown the label reads the configured hide label (Req 6.5).
|
|
764
|
+
* @return {string} The toggle button label.
|
|
765
|
+
* @memberof EventGroupCardComponent
|
|
766
|
+
*/
|
|
767
|
+
get meetingListToggleLabel() {
|
|
768
|
+
const toggle = this.constants?.eventGroupCard?.meetingListToggle;
|
|
769
|
+
if (this.isMeetingListOpen) {
|
|
770
|
+
return toggle?.hideLabel ?? 'Hide meetings';
|
|
771
|
+
}
|
|
772
|
+
return toggle?.showLabel ?? 'Show meetings';
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* The "{count} Meetings open for attendance" summary shown in the event's
|
|
776
|
+
* meetings bar, built from the `constants.json` template and the event's
|
|
777
|
+
* open-for-attendance count (Req 6.5).
|
|
778
|
+
* @return {string} The formatted open-for-attendance summary.
|
|
779
|
+
* @memberof EventGroupCardComponent
|
|
780
|
+
*/
|
|
781
|
+
get openForAttendanceSummary() {
|
|
782
|
+
const template = this.constants?.eventGroupCard?.openForAttendanceTemplate ??
|
|
783
|
+
'{count} Meetings open for attendance';
|
|
784
|
+
return template.replace('{count}', `${this.event?.openForAttendanceCount ?? 0}`);
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* The {@link MeetingRow} view model for a STANDALONE_MEETING card, projected
|
|
788
|
+
* from the event entry so the shared {@link MeetingAttendanceRowComponent}
|
|
789
|
+
* renders its time/timezone block and attendance action.
|
|
790
|
+
* @return {MeetingRow} The standalone meeting row.
|
|
791
|
+
* @memberof EventGroupCardComponent
|
|
792
|
+
*/
|
|
793
|
+
get standaloneMeeting() {
|
|
794
|
+
return {
|
|
795
|
+
meetingId: this.event?.eventId ?? '',
|
|
796
|
+
meetingName: this.event?.title ?? '',
|
|
797
|
+
groupOrCommittee: this.event?.groupOrCommittee,
|
|
798
|
+
roomOrLocation: this.event?.roomOrLocation,
|
|
799
|
+
startDateTime: this.event?.startDateTime ?? this.event?.startDate,
|
|
800
|
+
endDateTime: this.event?.endDateTime ?? this.event?.endDate,
|
|
801
|
+
timezone: this.event?.timezone ?? '',
|
|
802
|
+
status: this.event?.status,
|
|
803
|
+
isMemberOfGroup: this.event?.isMemberOfGroup,
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* The formatted "start – end time (timezone)" string for a STANDALONE meeting,
|
|
808
|
+
* mirroring the inner meeting row's TIME & TIMEZONE value.
|
|
809
|
+
* @return {string} The formatted time + timezone.
|
|
810
|
+
* @memberof EventGroupCardComponent
|
|
811
|
+
*/
|
|
812
|
+
get standaloneTime() {
|
|
813
|
+
const timezone = this.event?.timezone ?? '';
|
|
814
|
+
const start = formatEpoch(this.event?.startDateTime ?? this.event?.startDate, DateFormats.timeMeridiemFormat, timezone);
|
|
815
|
+
const end = formatEpoch(this.event?.endDateTime ?? this.event?.endDate, DateFormats.timeMeridiemFormat, timezone);
|
|
816
|
+
const range = end ? `${start} \u2013 ${end}` : start;
|
|
817
|
+
if (!range) {
|
|
818
|
+
return '';
|
|
819
|
+
}
|
|
820
|
+
return timezone ? `${range} ${timezone}` : range;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Whether the STANDALONE meeting is currently being attended (drives the pill
|
|
824
|
+
* and the leave action).
|
|
825
|
+
* @return {boolean} True when the standalone meeting is currently attending.
|
|
826
|
+
* @memberof EventGroupCardComponent
|
|
827
|
+
*/
|
|
828
|
+
get isStandaloneAttending() {
|
|
829
|
+
return (this.resolveAttendanceState(this.standaloneMeeting) ===
|
|
830
|
+
AttendanceState.CURRENTLY_ATTENDING);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Whether the STANDALONE meeting's Log Attendance button is shown (not
|
|
834
|
+
* attending and the host grants the permission).
|
|
835
|
+
* @return {boolean} True when the log-attendance button is visible.
|
|
836
|
+
* @memberof EventGroupCardComponent
|
|
837
|
+
*/
|
|
838
|
+
get showStandaloneLog() {
|
|
839
|
+
return !this.isStandaloneAttending && !!this.permissions?.canLogAttendance;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Whether the STANDALONE meeting's Leave Meeting button is shown (attending
|
|
843
|
+
* and the host grants the permission).
|
|
844
|
+
* @return {boolean} True when the leave-meeting button is visible.
|
|
845
|
+
* @memberof EventGroupCardComponent
|
|
846
|
+
*/
|
|
847
|
+
get showStandaloneLeave() {
|
|
848
|
+
return this.isStandaloneAttending && !!this.permissions?.canLeaveMeeting;
|
|
849
|
+
}
|
|
850
|
+
/** The luxon-formatted start date of the event (ISO or epoch ms) (Req 6.2). */
|
|
851
|
+
get formattedStartDate() {
|
|
852
|
+
return this.formatDate(this.event?.startDateTime ?? this.event?.startDate);
|
|
853
|
+
}
|
|
854
|
+
/** The luxon-formatted end date of the event (ISO or epoch ms) (Req 6.2). */
|
|
855
|
+
get formattedEndDate() {
|
|
856
|
+
return this.formatDate(this.event?.endDateTime ?? this.event?.endDate);
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* `trackBy` for the meeting-row `*ngFor`, keyed by the stable meeting id so
|
|
860
|
+
* Angular reuses row components across pagination/state changes (Req 6.7, 14.4).
|
|
861
|
+
* @param {number} _index - The iteration index (unused).
|
|
862
|
+
* @param {MeetingRow} meeting - The meeting for this row.
|
|
863
|
+
* @return {string} The stable track key (meeting id).
|
|
864
|
+
* @memberof EventGroupCardComponent
|
|
865
|
+
*/
|
|
866
|
+
trackByMeetingId(_index, meeting) {
|
|
867
|
+
return meeting?.meetingId ?? `${_index}`;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Resolves the attendance state for a meeting from the `attendanceStates` map,
|
|
871
|
+
* defaulting to `NOT_ATTENDING` when the map has no entry for it.
|
|
872
|
+
* @param {MeetingRow} meeting - The meeting to resolve state for.
|
|
873
|
+
* @return {AttendanceState} The attendance state passed to the row.
|
|
874
|
+
* @memberof EventGroupCardComponent
|
|
875
|
+
*/
|
|
876
|
+
resolveAttendanceState(meeting) {
|
|
877
|
+
return (this.attendanceStates?.[meeting?.meetingId] ??
|
|
878
|
+
AttendanceState.NOT_ATTENDING);
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Resolves whether a meeting has an attendance action in flight from the
|
|
882
|
+
* `inFlightMeetingIds` set.
|
|
883
|
+
* @param {MeetingRow} meeting - The meeting to check.
|
|
884
|
+
* @return {boolean} True when the meeting's action is awaiting resolution.
|
|
885
|
+
* @memberof EventGroupCardComponent
|
|
886
|
+
*/
|
|
887
|
+
resolveIsInFlight(meeting) {
|
|
888
|
+
return this.inFlightMeetingIds?.has(meeting?.meetingId) ?? false;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Toggles the meeting-list visibility, lazily requesting the first page of the
|
|
892
|
+
* event's child meetings from the container the first time it is opened (Req 6.6).
|
|
893
|
+
* @memberof EventGroupCardComponent
|
|
894
|
+
*/
|
|
895
|
+
onToggleMeetingList() {
|
|
896
|
+
this.isMeetingListOpen = !this.isMeetingListOpen;
|
|
897
|
+
if (this.isMeetingListOpen) {
|
|
898
|
+
this.loadMeetings.emit(this.pageIndex + 1);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Handles the "View Event" button, emitting the event id to the host (Req 6.4).
|
|
903
|
+
* @memberof EventGroupCardComponent
|
|
904
|
+
*/
|
|
905
|
+
onViewEvent() {
|
|
906
|
+
this.viewEvent.emit(this.event?.eventId);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Bubbles a row's meeting-name link activation upward (Req 6.7, 7.4).
|
|
910
|
+
* @param {string} meetingId - The id emitted by the row.
|
|
911
|
+
* @memberof EventGroupCardComponent
|
|
912
|
+
*/
|
|
913
|
+
onOpenMeeting(meetingId) {
|
|
914
|
+
this.openMeeting.emit(meetingId);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Bubbles a row's log-attendance request upward (Req 6.7, 7.7).
|
|
918
|
+
* @param {string} meetingId - The id emitted by the row.
|
|
919
|
+
* @memberof EventGroupCardComponent
|
|
920
|
+
*/
|
|
921
|
+
onLogAttendance(meetingId) {
|
|
922
|
+
this.logAttendance.emit(meetingId);
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Bubbles a row's leave-meeting request upward (Req 6.7, 7.8).
|
|
926
|
+
* @param {string} meetingId - The id emitted by the row.
|
|
927
|
+
* @memberof EventGroupCardComponent
|
|
928
|
+
*/
|
|
929
|
+
onLeaveMeeting(meetingId) {
|
|
930
|
+
this.leaveMeeting.emit(meetingId);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Handles the per-card paginator change, updating the local page state and
|
|
934
|
+
* emitting the requested page as a {@link PageChange} (Req 6.9, 3.3).
|
|
935
|
+
* @param {PageEvent} event - The Material paginator page event.
|
|
936
|
+
* @memberof EventGroupCardComponent
|
|
937
|
+
*/
|
|
938
|
+
onPageChange(event) {
|
|
939
|
+
this.pageIndex = event.pageIndex;
|
|
940
|
+
this.pageSize = event.pageSize;
|
|
941
|
+
this.pageChange.emit({
|
|
942
|
+
pageIndex: event.pageIndex,
|
|
943
|
+
pageSize: event.pageSize,
|
|
944
|
+
});
|
|
945
|
+
// Request the newly selected page's child meetings from the container.
|
|
946
|
+
this.loadMeetings.emit(event.pageIndex + 1);
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Formats a date for display, preferring the epoch-milliseconds value (from
|
|
950
|
+
* the real API) formatted in the event's timezone and falling back to a legacy
|
|
951
|
+
* ISO string. Returns an empty string when neither is present.
|
|
952
|
+
* @param {number | undefined} epochMs - The epoch-milliseconds value.
|
|
953
|
+
* @param {string | undefined} isoValue - The legacy ISO fallback.
|
|
954
|
+
* @return {string} The formatted date or an empty string.
|
|
955
|
+
* @memberof EventGroupCardComponent
|
|
956
|
+
*/
|
|
957
|
+
formatDate(value) {
|
|
958
|
+
return formatEpoch(value, DateFormats.displayFormat, this.event?.timezone);
|
|
959
|
+
}
|
|
960
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EventGroupCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
961
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EventGroupCardComponent, isStandalone: true, selector: "ieeesa-event-group-card", inputs: { event: "event", permissions: "permissions", attendanceStates: "attendanceStates", inFlightMeetingIds: "inFlightMeetingIds", isMobileView: "isMobileView" }, outputs: { viewEvent: "viewEvent", openMeeting: "openMeeting", logAttendance: "logAttendance", leaveMeeting: "leaveMeeting", pageChange: "pageChange", loadMeetings: "loadMeetings" }, ngImport: i0, template: "<article\r\n class=\"ieeesa-event-group-card\"\r\n [class.ieeesa-event-group-card--mobile]=\"isMobileView\"\r\n [class.ieeesa-event-group-card--standalone]=\"isStandalone\"\r\n>\r\n <!-- ============================ EVENT ============================ -->\r\n <ng-container *ngIf=\"!isStandalone\">\r\n <header class=\"ieeesa-event-group-card__header\">\r\n <div class=\"ieeesa-event-group-card__header-main\">\r\n <!-- EVENT badge + day indicator. -->\r\n <div class=\"ieeesa-event-group-card__badge-row\">\r\n <span class=\"ieeesa-event-group-card__badge\">\r\n {{ constants.eventGroupCard.eventBadge }}\r\n </span>\r\n <span\r\n *ngIf=\"event.dayIndicator\"\r\n class=\"ieeesa-event-group-card__day-indicator\"\r\n >\r\n {{ event.dayIndicator }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"ieeesa-event-group-card__title-row\">\r\n <h3 class=\"ieeesa-event-group-card__title\">{{ event.title }}</h3>\r\n <span\r\n *ngIf=\"event.status\"\r\n class=\"ieeesa-event-group-card__status-pill\"\r\n [ngClass]=\"'ieeesa-event-group-card__status-pill--' + statusModifier\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ event.status }}\r\n </span>\r\n </div>\r\n\r\n <p\r\n *ngIf=\"subtitleText\"\r\n class=\"ieeesa-event-group-card__subtitle\"\r\n >\r\n {{ subtitleText }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"ieeesa-event-group-card__header-side\">\r\n <dl class=\"ieeesa-event-group-card__dates-block\">\r\n <dt class=\"ieeesa-event-group-card__dates-label\">\r\n {{ constants.eventGroupCard.eventDatesLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__dates-value\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate && formattedEndDate !== formattedStartDate\">\r\n – {{ formattedEndDate }}</ng-container>\r\n </dd>\r\n <dd\r\n *ngIf=\"event.timezone\"\r\n class=\"ieeesa-event-group-card__timezone-value\"\r\n >\r\n {{ event.timezone }}\r\n </dd>\r\n </dl>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__view\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.viewEvent\"\r\n (click)=\"onViewEvent()\"\r\n >\r\n {{ constants.eventGroupCard.viewEventLabel }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <!-- Meetings label row + Show/Hide toggle. -->\r\n <div class=\"ieeesa-event-group-card__meetings-bar\">\r\n <span class=\"ieeesa-event-group-card__meetings-open\">\r\n <span class=\"ieeesa-event-group-card__meetings-dot\" aria-hidden=\"true\"></span>\r\n {{ openForAttendanceSummary }}\r\n </span>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__meeting-toggle\"\r\n [attr.aria-expanded]=\"isMeetingListOpen\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.meetingListToggle\"\r\n (click)=\"onToggleMeetingList()\"\r\n >\r\n <span>{{ meetingListToggleLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isMeetingListOpen ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Expanded inner meeting list + per-event paginator. -->\r\n <div\r\n *ngIf=\"isMeetingListOpen\"\r\n class=\"ieeesa-event-group-card__meetings\"\r\n >\r\n <ieeesa-meeting-attendance-row\r\n *ngFor=\"let meeting of pagedMeetings; trackBy: trackByMeetingId\"\r\n [meeting]=\"meeting\"\r\n [attendanceState]=\"resolveAttendanceState(meeting)\"\r\n [isInFlight]=\"resolveIsInFlight(meeting)\"\r\n [permissions]=\"permissions\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n ></ieeesa-meeting-attendance-row>\r\n\r\n <div\r\n class=\"ieeesa-event-group-card__paginator\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.meetingListToggle\"\r\n >\r\n <span class=\"ieeesa-event-group-card__paginator-range\">\r\n {{ rangeLabel }}\r\n </span>\r\n\r\n <mat-paginator\r\n class=\"ieeesa-event-group-card__paginator-control\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSize]=\"pageSize\"\r\n [length]=\"totalMeetings\"\r\n [hidePageSize]=\"true\"\r\n (page)=\"onPageChange($event)\"\r\n ></mat-paginator>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- ======================= STANDALONE MEETING ======================= -->\r\n <!-- Single horizontal row: badge+name+subtitle | MEETING DATE | TIME & TIMEZONE | action. -->\r\n <div *ngIf=\"isStandalone\" class=\"ieeesa-event-group-card__standalone\">\r\n <div class=\"ieeesa-event-group-card__standalone-main\">\r\n <span class=\"ieeesa-event-group-card__badge ieeesa-event-group-card__badge--standalone\">\r\n {{ constants.eventGroupCard.standaloneBadge }}\r\n </span>\r\n\r\n <div class=\"ieeesa-event-group-card__standalone-title-row\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-name\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.meetingNameLink\"\r\n (click)=\"onOpenMeeting(event.eventId)\"\r\n >\r\n {{ event.title }}\r\n </button>\r\n <span\r\n *ngIf=\"event.status\"\r\n class=\"ieeesa-event-group-card__status-pill\"\r\n [ngClass]=\"'ieeesa-event-group-card__status-pill--' + statusModifier\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ event.status }}\r\n </span>\r\n </div>\r\n\r\n <p\r\n *ngIf=\"subtitleText\"\r\n class=\"ieeesa-event-group-card__standalone-subtitle\"\r\n >\r\n {{ subtitleText }}\r\n </p>\r\n </div>\r\n\r\n <!-- MEETING DATE column. -->\r\n <dl class=\"ieeesa-event-group-card__standalone-col\">\r\n <dt class=\"ieeesa-event-group-card__standalone-col-label\">\r\n {{ constants.eventGroupCard.meetingDateLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__standalone-col-value\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate && formattedEndDate !== formattedStartDate\">\r\n – {{ formattedEndDate }}</ng-container>\r\n </dd>\r\n </dl>\r\n\r\n <!-- TIME & TIMEZONE column. -->\r\n <dl class=\"ieeesa-event-group-card__standalone-col\">\r\n <dt class=\"ieeesa-event-group-card__standalone-col-label\">\r\n {{ constants.eventGroupCard.timeTimezoneLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__standalone-col-value\">\r\n {{ standaloneTime }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- Attendance action column. -->\r\n <div class=\"ieeesa-event-group-card__standalone-actions\">\r\n <span\r\n *ngIf=\"isStandaloneAttending\"\r\n class=\"ieeesa-event-group-card__attending-pill\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ constants.meetingRow.currentlyAttendingIndicator }}\r\n </span>\r\n\r\n <button\r\n *ngIf=\"showStandaloneLog\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--log\"\r\n [disabled]=\"resolveIsInFlight(standaloneMeeting)\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.logAttendance\"\r\n (click)=\"onLogAttendance(event.eventId)\"\r\n >\r\n {{ constants.meetingRow.logAttendanceLabel }}\r\n </button>\r\n\r\n <button\r\n *ngIf=\"showStandaloneLeave\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--leave\"\r\n [disabled]=\"resolveIsInFlight(standaloneMeeting)\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.leaveMeeting\"\r\n (click)=\"onLeaveMeeting(event.eventId)\"\r\n >\r\n {{ constants.meetingRow.leaveMeetingLabel }}\r\n </button>\r\n </div>\r\n </div>\r\n</article>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-event-group-card{display:flex;flex-direction:column;gap:16px;padding:20px 24px;border:1px solid #d7d6d6;border-radius:8px;background-color:#fff;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026;font-family:Calibri Regular}.ieeesa-event-group-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:24px}.ieeesa-event-group-card__header-main{display:flex;flex-direction:column;gap:8px;min-width:0}.ieeesa-event-group-card__badge-row{display:flex;align-items:center;gap:12px}.ieeesa-event-group-card__badge{display:inline-flex;align-items:center;padding:4px 12px;border-radius:4px;font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#00629b;background-color:#eaf3f9}.ieeesa-event-group-card__badge--standalone{color:#333436;background-color:#f0f0f0}.ieeesa-event-group-card__day-indicator{font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__title-row{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.ieeesa-event-group-card__title{margin:0;font-family:Calibri Bold;font-size:1.25rem;line-height:24px;color:#333436}.ieeesa-event-group-card__status-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 12px;border-radius:16px;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-event-group-card__status-pill--upcoming,.ieeesa-event-group-card__status-pill--starts-soon{color:#8a6d00;background-color:#fef7e0}.ieeesa-event-group-card__status-pill--upcoming .ieeesa-event-group-card__status-dot,.ieeesa-event-group-card__status-pill--starts-soon .ieeesa-event-group-card__status-dot{background-color:#e5a200}.ieeesa-event-group-card__status-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-event-group-card__subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__header-side{display:flex;align-items:flex-start;gap:24px;flex-shrink:0}.ieeesa-event-group-card__dates-block{display:flex;flex-direction:column;gap:2px;margin:0;text-align:right}.ieeesa-event-group-card__dates-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-event-group-card__dates-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__timezone-value{margin:0;font-size:.8125rem;color:#939094}.ieeesa-event-group-card__view{flex-shrink:0;min-width:122px;padding:8px 16px;border:1px solid #00629b;border-radius:4px;background-color:#fff;font-size:.875rem;color:#00629b;cursor:pointer}.ieeesa-event-group-card__view:hover{background-color:#eaf3f9}.ieeesa-event-group-card__meetings-bar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;padding-top:16px;border-top:1px solid #d7d6d6}.ieeesa-event-group-card__meetings-open{display:inline-flex;align-items:center;gap:8px;font-size:.875rem;color:#333436}.ieeesa-event-group-card__meetings-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-event-group-card__meeting-toggle{display:inline-flex;align-items:center;gap:8px;padding:8px 0;border:0;background:none;font-size:.875rem;color:#00629b;cursor:pointer}.ieeesa-event-group-card__meetings{display:flex;flex-direction:column;border:1px solid #d7d6d6;border-radius:8px;overflow:hidden}.ieeesa-event-group-card__paginator{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;padding:12px 20px;border-top:1px solid #d7d6d6}.ieeesa-event-group-card__paginator-range{font-size:.8125rem;color:#939094}.ieeesa-event-group-card__standalone{display:grid;grid-template-columns:minmax(260px,2.4fr) minmax(130px,1fr) minmax(200px,1.3fr) auto;align-items:center;column-gap:24px}.ieeesa-event-group-card__standalone-main{display:flex;flex-direction:column;gap:6px;min-width:0}.ieeesa-event-group-card__standalone-title-row{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.ieeesa-event-group-card__standalone-name{padding:0;border:0;background:none;text-align:left;text-decoration:underline;font-family:Calibri Bold;font-size:1rem;line-height:20px;color:#00629b;cursor:pointer}.ieeesa-event-group-card__standalone-subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__standalone-col{display:flex;flex-direction:column;gap:4px;margin:0;min-width:0}.ieeesa-event-group-card__standalone-col-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-event-group-card__standalone-col-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__standalone-actions{display:flex;align-items:center;justify-content:flex-end;gap:16px}.ieeesa-event-group-card__attending-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;white-space:nowrap;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-event-group-card__standalone-action{min-width:146px;padding:10px 16px;border-radius:4px;font-family:Calibri Bold;font-size:.875rem;cursor:pointer}.ieeesa-event-group-card__standalone-action--log{border:1px solid #00629b;background-color:#00629b;color:#fff}.ieeesa-event-group-card__standalone-action--leave{border:1px solid #00629b;background-color:#fff;color:#00629b}.ieeesa-event-group-card__standalone-action:disabled{border-color:#939094;background-color:#939094;color:#fff;cursor:default}.ieeesa-event-group-card--mobile{padding:16px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__header{flex-direction:column;align-items:stretch}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__header-side{flex-direction:column;align-items:stretch;gap:12px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__dates-block{text-align:left}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__view{align-self:stretch;width:100%}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__paginator{flex-direction:column;align-items:stretch}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__standalone{grid-template-columns:1fr;row-gap:12px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__standalone-actions{justify-content:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i2.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: MeetingAttendanceRowComponent, selector: "ieeesa-meeting-attendance-row", inputs: ["meeting", "attendanceState", "isInFlight", "permissions", "compact"], outputs: ["openMeeting", "logAttendance", "leaveMeeting"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
962
|
+
}
|
|
963
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EventGroupCardComponent, decorators: [{
|
|
964
|
+
type: Component,
|
|
965
|
+
args: [{ selector: 'ieeesa-event-group-card', standalone: true, imports: [CommonModule, MatPaginatorModule, MeetingAttendanceRowComponent], encapsulation: ViewEncapsulation.None, template: "<article\r\n class=\"ieeesa-event-group-card\"\r\n [class.ieeesa-event-group-card--mobile]=\"isMobileView\"\r\n [class.ieeesa-event-group-card--standalone]=\"isStandalone\"\r\n>\r\n <!-- ============================ EVENT ============================ -->\r\n <ng-container *ngIf=\"!isStandalone\">\r\n <header class=\"ieeesa-event-group-card__header\">\r\n <div class=\"ieeesa-event-group-card__header-main\">\r\n <!-- EVENT badge + day indicator. -->\r\n <div class=\"ieeesa-event-group-card__badge-row\">\r\n <span class=\"ieeesa-event-group-card__badge\">\r\n {{ constants.eventGroupCard.eventBadge }}\r\n </span>\r\n <span\r\n *ngIf=\"event.dayIndicator\"\r\n class=\"ieeesa-event-group-card__day-indicator\"\r\n >\r\n {{ event.dayIndicator }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"ieeesa-event-group-card__title-row\">\r\n <h3 class=\"ieeesa-event-group-card__title\">{{ event.title }}</h3>\r\n <span\r\n *ngIf=\"event.status\"\r\n class=\"ieeesa-event-group-card__status-pill\"\r\n [ngClass]=\"'ieeesa-event-group-card__status-pill--' + statusModifier\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ event.status }}\r\n </span>\r\n </div>\r\n\r\n <p\r\n *ngIf=\"subtitleText\"\r\n class=\"ieeesa-event-group-card__subtitle\"\r\n >\r\n {{ subtitleText }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"ieeesa-event-group-card__header-side\">\r\n <dl class=\"ieeesa-event-group-card__dates-block\">\r\n <dt class=\"ieeesa-event-group-card__dates-label\">\r\n {{ constants.eventGroupCard.eventDatesLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__dates-value\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate && formattedEndDate !== formattedStartDate\">\r\n – {{ formattedEndDate }}</ng-container>\r\n </dd>\r\n <dd\r\n *ngIf=\"event.timezone\"\r\n class=\"ieeesa-event-group-card__timezone-value\"\r\n >\r\n {{ event.timezone }}\r\n </dd>\r\n </dl>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__view\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.viewEvent\"\r\n (click)=\"onViewEvent()\"\r\n >\r\n {{ constants.eventGroupCard.viewEventLabel }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <!-- Meetings label row + Show/Hide toggle. -->\r\n <div class=\"ieeesa-event-group-card__meetings-bar\">\r\n <span class=\"ieeesa-event-group-card__meetings-open\">\r\n <span class=\"ieeesa-event-group-card__meetings-dot\" aria-hidden=\"true\"></span>\r\n {{ openForAttendanceSummary }}\r\n </span>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__meeting-toggle\"\r\n [attr.aria-expanded]=\"isMeetingListOpen\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.meetingListToggle\"\r\n (click)=\"onToggleMeetingList()\"\r\n >\r\n <span>{{ meetingListToggleLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isMeetingListOpen ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Expanded inner meeting list + per-event paginator. -->\r\n <div\r\n *ngIf=\"isMeetingListOpen\"\r\n class=\"ieeesa-event-group-card__meetings\"\r\n >\r\n <ieeesa-meeting-attendance-row\r\n *ngFor=\"let meeting of pagedMeetings; trackBy: trackByMeetingId\"\r\n [meeting]=\"meeting\"\r\n [attendanceState]=\"resolveAttendanceState(meeting)\"\r\n [isInFlight]=\"resolveIsInFlight(meeting)\"\r\n [permissions]=\"permissions\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n ></ieeesa-meeting-attendance-row>\r\n\r\n <div\r\n class=\"ieeesa-event-group-card__paginator\"\r\n [attr.aria-label]=\"constants.eventGroupCard.ariaLabel.meetingListToggle\"\r\n >\r\n <span class=\"ieeesa-event-group-card__paginator-range\">\r\n {{ rangeLabel }}\r\n </span>\r\n\r\n <mat-paginator\r\n class=\"ieeesa-event-group-card__paginator-control\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSize]=\"pageSize\"\r\n [length]=\"totalMeetings\"\r\n [hidePageSize]=\"true\"\r\n (page)=\"onPageChange($event)\"\r\n ></mat-paginator>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- ======================= STANDALONE MEETING ======================= -->\r\n <!-- Single horizontal row: badge+name+subtitle | MEETING DATE | TIME & TIMEZONE | action. -->\r\n <div *ngIf=\"isStandalone\" class=\"ieeesa-event-group-card__standalone\">\r\n <div class=\"ieeesa-event-group-card__standalone-main\">\r\n <span class=\"ieeesa-event-group-card__badge ieeesa-event-group-card__badge--standalone\">\r\n {{ constants.eventGroupCard.standaloneBadge }}\r\n </span>\r\n\r\n <div class=\"ieeesa-event-group-card__standalone-title-row\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-name\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.meetingNameLink\"\r\n (click)=\"onOpenMeeting(event.eventId)\"\r\n >\r\n {{ event.title }}\r\n </button>\r\n <span\r\n *ngIf=\"event.status\"\r\n class=\"ieeesa-event-group-card__status-pill\"\r\n [ngClass]=\"'ieeesa-event-group-card__status-pill--' + statusModifier\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ event.status }}\r\n </span>\r\n </div>\r\n\r\n <p\r\n *ngIf=\"subtitleText\"\r\n class=\"ieeesa-event-group-card__standalone-subtitle\"\r\n >\r\n {{ subtitleText }}\r\n </p>\r\n </div>\r\n\r\n <!-- MEETING DATE column. -->\r\n <dl class=\"ieeesa-event-group-card__standalone-col\">\r\n <dt class=\"ieeesa-event-group-card__standalone-col-label\">\r\n {{ constants.eventGroupCard.meetingDateLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__standalone-col-value\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate && formattedEndDate !== formattedStartDate\">\r\n – {{ formattedEndDate }}</ng-container>\r\n </dd>\r\n </dl>\r\n\r\n <!-- TIME & TIMEZONE column. -->\r\n <dl class=\"ieeesa-event-group-card__standalone-col\">\r\n <dt class=\"ieeesa-event-group-card__standalone-col-label\">\r\n {{ constants.eventGroupCard.timeTimezoneLabel }}\r\n </dt>\r\n <dd class=\"ieeesa-event-group-card__standalone-col-value\">\r\n {{ standaloneTime }}\r\n </dd>\r\n </dl>\r\n\r\n <!-- Attendance action column. -->\r\n <div class=\"ieeesa-event-group-card__standalone-actions\">\r\n <span\r\n *ngIf=\"isStandaloneAttending\"\r\n class=\"ieeesa-event-group-card__attending-pill\"\r\n >\r\n <span class=\"ieeesa-event-group-card__status-dot\" aria-hidden=\"true\"></span>\r\n {{ constants.meetingRow.currentlyAttendingIndicator }}\r\n </span>\r\n\r\n <button\r\n *ngIf=\"showStandaloneLog\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--log\"\r\n [disabled]=\"resolveIsInFlight(standaloneMeeting)\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.logAttendance\"\r\n (click)=\"onLogAttendance(event.eventId)\"\r\n >\r\n {{ constants.meetingRow.logAttendanceLabel }}\r\n </button>\r\n\r\n <button\r\n *ngIf=\"showStandaloneLeave\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--leave\"\r\n [disabled]=\"resolveIsInFlight(standaloneMeeting)\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.leaveMeeting\"\r\n (click)=\"onLeaveMeeting(event.eventId)\"\r\n >\r\n {{ constants.meetingRow.leaveMeetingLabel }}\r\n </button>\r\n </div>\r\n </div>\r\n</article>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-event-group-card{display:flex;flex-direction:column;gap:16px;padding:20px 24px;border:1px solid #d7d6d6;border-radius:8px;background-color:#fff;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026;font-family:Calibri Regular}.ieeesa-event-group-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:24px}.ieeesa-event-group-card__header-main{display:flex;flex-direction:column;gap:8px;min-width:0}.ieeesa-event-group-card__badge-row{display:flex;align-items:center;gap:12px}.ieeesa-event-group-card__badge{display:inline-flex;align-items:center;padding:4px 12px;border-radius:4px;font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#00629b;background-color:#eaf3f9}.ieeesa-event-group-card__badge--standalone{color:#333436;background-color:#f0f0f0}.ieeesa-event-group-card__day-indicator{font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__title-row{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.ieeesa-event-group-card__title{margin:0;font-family:Calibri Bold;font-size:1.25rem;line-height:24px;color:#333436}.ieeesa-event-group-card__status-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 12px;border-radius:16px;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-event-group-card__status-pill--upcoming,.ieeesa-event-group-card__status-pill--starts-soon{color:#8a6d00;background-color:#fef7e0}.ieeesa-event-group-card__status-pill--upcoming .ieeesa-event-group-card__status-dot,.ieeesa-event-group-card__status-pill--starts-soon .ieeesa-event-group-card__status-dot{background-color:#e5a200}.ieeesa-event-group-card__status-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-event-group-card__subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__header-side{display:flex;align-items:flex-start;gap:24px;flex-shrink:0}.ieeesa-event-group-card__dates-block{display:flex;flex-direction:column;gap:2px;margin:0;text-align:right}.ieeesa-event-group-card__dates-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-event-group-card__dates-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__timezone-value{margin:0;font-size:.8125rem;color:#939094}.ieeesa-event-group-card__view{flex-shrink:0;min-width:122px;padding:8px 16px;border:1px solid #00629b;border-radius:4px;background-color:#fff;font-size:.875rem;color:#00629b;cursor:pointer}.ieeesa-event-group-card__view:hover{background-color:#eaf3f9}.ieeesa-event-group-card__meetings-bar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;padding-top:16px;border-top:1px solid #d7d6d6}.ieeesa-event-group-card__meetings-open{display:inline-flex;align-items:center;gap:8px;font-size:.875rem;color:#333436}.ieeesa-event-group-card__meetings-dot{width:8px;height:8px;border-radius:50%;background-color:#1a7f37}.ieeesa-event-group-card__meeting-toggle{display:inline-flex;align-items:center;gap:8px;padding:8px 0;border:0;background:none;font-size:.875rem;color:#00629b;cursor:pointer}.ieeesa-event-group-card__meetings{display:flex;flex-direction:column;border:1px solid #d7d6d6;border-radius:8px;overflow:hidden}.ieeesa-event-group-card__paginator{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;padding:12px 20px;border-top:1px solid #d7d6d6}.ieeesa-event-group-card__paginator-range{font-size:.8125rem;color:#939094}.ieeesa-event-group-card__standalone{display:grid;grid-template-columns:minmax(260px,2.4fr) minmax(130px,1fr) minmax(200px,1.3fr) auto;align-items:center;column-gap:24px}.ieeesa-event-group-card__standalone-main{display:flex;flex-direction:column;gap:6px;min-width:0}.ieeesa-event-group-card__standalone-title-row{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.ieeesa-event-group-card__standalone-name{padding:0;border:0;background:none;text-align:left;text-decoration:underline;font-family:Calibri Bold;font-size:1rem;line-height:20px;color:#00629b;cursor:pointer}.ieeesa-event-group-card__standalone-subtitle{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__standalone-col{display:flex;flex-direction:column;gap:4px;margin:0;min-width:0}.ieeesa-event-group-card__standalone-col-label{font-family:Calibri Bold;font-size:.75rem;letter-spacing:.03125em;text-transform:uppercase;color:#939094}.ieeesa-event-group-card__standalone-col-value{margin:0;font-size:.875rem;line-height:18px;color:#333436}.ieeesa-event-group-card__standalone-actions{display:flex;align-items:center;justify-content:flex-end;gap:16px}.ieeesa-event-group-card__attending-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;white-space:nowrap;font-size:.8125rem;color:#1a7f37;background-color:#e8f5ec}.ieeesa-event-group-card__standalone-action{min-width:146px;padding:10px 16px;border-radius:4px;font-family:Calibri Bold;font-size:.875rem;cursor:pointer}.ieeesa-event-group-card__standalone-action--log{border:1px solid #00629b;background-color:#00629b;color:#fff}.ieeesa-event-group-card__standalone-action--leave{border:1px solid #00629b;background-color:#fff;color:#00629b}.ieeesa-event-group-card__standalone-action:disabled{border-color:#939094;background-color:#939094;color:#fff;cursor:default}.ieeesa-event-group-card--mobile{padding:16px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__header{flex-direction:column;align-items:stretch}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__header-side{flex-direction:column;align-items:stretch;gap:12px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__dates-block{text-align:left}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__view{align-self:stretch;width:100%}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__paginator{flex-direction:column;align-items:stretch}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__standalone{grid-template-columns:1fr;row-gap:12px}.ieeesa-event-group-card--mobile .ieeesa-event-group-card__standalone-actions{justify-content:flex-start}\n"] }]
|
|
966
|
+
}], propDecorators: { event: [{
|
|
967
|
+
type: Input
|
|
968
|
+
}], permissions: [{
|
|
969
|
+
type: Input
|
|
970
|
+
}], attendanceStates: [{
|
|
971
|
+
type: Input
|
|
972
|
+
}], inFlightMeetingIds: [{
|
|
973
|
+
type: Input
|
|
974
|
+
}], isMobileView: [{
|
|
975
|
+
type: Input
|
|
976
|
+
}], viewEvent: [{
|
|
977
|
+
type: Output
|
|
978
|
+
}], openMeeting: [{
|
|
979
|
+
type: Output
|
|
980
|
+
}], logAttendance: [{
|
|
981
|
+
type: Output
|
|
982
|
+
}], leaveMeeting: [{
|
|
983
|
+
type: Output
|
|
984
|
+
}], pageChange: [{
|
|
985
|
+
type: Output
|
|
986
|
+
}], loadMeetings: [{
|
|
987
|
+
type: Output
|
|
988
|
+
}] } });
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Upcoming_Meetings_Events renders the "Upcoming Meetings & Events" dashboard
|
|
992
|
+
* section: a section title and "View All" link, a collapse/expand toggle that
|
|
993
|
+
* starts expanded, and one {@link EventGroupCardComponent} per upcoming event.
|
|
994
|
+
*
|
|
995
|
+
* The section is driven by its `sectionState` input: it shows the Loader while
|
|
996
|
+
* `LOADING`, the event-group cards while `LOADED`, the empty-state message while
|
|
997
|
+
* `EMPTY`, and the error message while `ERROR` — the four regions are mutually
|
|
998
|
+
* exclusive (Req 13.1, 13.2, 13.3, 13.5). The component is purely
|
|
999
|
+
* presentational: "View All" emits `viewAll` (Req 5.1, 5.2), the collapse toggle
|
|
1000
|
+
* flips `isExpanded` and the card-list visibility while exposing
|
|
1001
|
+
* `[attr.aria-expanded]` (Req 5.3, 5.4, 14.3), and each card is rendered via
|
|
1002
|
+
* `*ngFor` with {@link trackByEventId} to preserve input order (Req 5.5, 5.6,
|
|
1003
|
+
* 14.4). Card outputs (`viewEvent`/`openMeeting`/`logAttendance`/`leaveMeeting`)
|
|
1004
|
+
* are bubbled upward unchanged, and each card's `pageChange` is mapped to
|
|
1005
|
+
* `meetingPageChange` tagged with the originating event id (Req 6.9).
|
|
1006
|
+
* @export
|
|
1007
|
+
* @class UpcomingMeetingsEventsComponent
|
|
1008
|
+
*/
|
|
1009
|
+
class UpcomingMeetingsEventsComponent {
|
|
1010
|
+
constructor() {
|
|
1011
|
+
/** User-facing strings sourced from `constants.json`. */
|
|
1012
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1013
|
+
this.constants = constants$1;
|
|
1014
|
+
/** Enum reference for template comparisons against `sectionState`. */
|
|
1015
|
+
this.sectionStates = DashboardSectionState;
|
|
1016
|
+
/** The upcoming events rendered as event-group cards (Req 5.5, 5.6). */
|
|
1017
|
+
this.events = [];
|
|
1018
|
+
/** The load/empty/error status driving the section's mutually exclusive regions. */
|
|
1019
|
+
this.sectionState = DashboardSectionState.LOADING;
|
|
1020
|
+
/** Host permissions gating the per-row log-attendance / leave-meeting buttons. */
|
|
1021
|
+
this.permissions = {
|
|
1022
|
+
canLogAttendance: false,
|
|
1023
|
+
canLeaveMeeting: false,
|
|
1024
|
+
};
|
|
1025
|
+
/** Map of meeting id to current attendance state, passed down to each card. */
|
|
1026
|
+
this.attendanceStates = {};
|
|
1027
|
+
/** Set of meeting ids with an attendance action awaiting resolution. */
|
|
1028
|
+
this.inFlightMeetingIds = new Set();
|
|
1029
|
+
/** Whether the host has determined the viewport is at/below the mobile breakpoint. */
|
|
1030
|
+
this.isMobileView = false;
|
|
1031
|
+
/** Emits when the "View All" link is activated (Req 5.2). */
|
|
1032
|
+
this.viewAll = new EventEmitter();
|
|
1033
|
+
/** Bubbles the event id when a card's "View Event" button is activated (Req 6.4). */
|
|
1034
|
+
this.viewEvent = new EventEmitter();
|
|
1035
|
+
/** Bubbles the meeting id when a card's meeting-name link is activated (Req 7.4). */
|
|
1036
|
+
this.openMeeting = new EventEmitter();
|
|
1037
|
+
/** Bubbles the meeting id when a card requests logging attendance (Req 7.7). */
|
|
1038
|
+
this.logAttendance = new EventEmitter();
|
|
1039
|
+
/** Bubbles the meeting id when a card requests leaving the meeting (Req 7.8). */
|
|
1040
|
+
this.leaveMeeting = new EventEmitter();
|
|
1041
|
+
/** Emits the requested page tagged with its event id when a card paginates (Req 6.9). */
|
|
1042
|
+
this.meetingPageChange = new EventEmitter();
|
|
1043
|
+
/** Emits the event id + one-based page to lazily load an event's child meetings. */
|
|
1044
|
+
this.loadEventMeetings = new EventEmitter();
|
|
1045
|
+
/** Whether the section's card list is currently expanded; starts collapsed. */
|
|
1046
|
+
this.isExpanded = false;
|
|
1047
|
+
/** Section-level page size — 5 events/meetings per page per the design. */
|
|
1048
|
+
this.sectionPageSize = 5;
|
|
1049
|
+
/** The current zero-based page index of the section list. */
|
|
1050
|
+
this.sectionPageIndex = 0;
|
|
1051
|
+
/**
|
|
1052
|
+
* Emits the new expanded state whenever the user toggles the section, so a
|
|
1053
|
+
* two-way `[(expanded)]` binding keeps the host's flag in sync (otherwise a
|
|
1054
|
+
* host-opened section the user then collapses leaves the host flag stale,
|
|
1055
|
+
* making a repeat "Jump to" a no-op).
|
|
1056
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1057
|
+
*/
|
|
1058
|
+
this.expandedChange = new EventEmitter();
|
|
1059
|
+
}
|
|
1060
|
+
/** The total number of events/meetings in the section (paginator length). */
|
|
1061
|
+
get totalItems() {
|
|
1062
|
+
return this.events?.length ?? 0;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* The slice of events/meetings for the current section page (5 per page),
|
|
1066
|
+
* used by the card `*ngFor`.
|
|
1067
|
+
* @return {UpcomingEvent[]} The events on the current page.
|
|
1068
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1069
|
+
*/
|
|
1070
|
+
get pagedEvents() {
|
|
1071
|
+
const start = this.sectionPageIndex * this.sectionPageSize;
|
|
1072
|
+
return (this.events ?? []).slice(start, start + this.sectionPageSize);
|
|
1073
|
+
}
|
|
1074
|
+
/** The one-based index of the first item shown on the current page. */
|
|
1075
|
+
get sectionRangeStart() {
|
|
1076
|
+
return this.totalItems === 0
|
|
1077
|
+
? 0
|
|
1078
|
+
: this.sectionPageIndex * this.sectionPageSize + 1;
|
|
1079
|
+
}
|
|
1080
|
+
/** The one-based index of the last item shown on the current page. */
|
|
1081
|
+
get sectionRangeEnd() {
|
|
1082
|
+
return Math.min((this.sectionPageIndex + 1) * this.sectionPageSize, this.totalItems);
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* The section paginator range label (e.g. "1-5 of 20 Meetings & Events")
|
|
1086
|
+
* built from the `constants.json` template.
|
|
1087
|
+
* @return {string} The formatted range label.
|
|
1088
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1089
|
+
*/
|
|
1090
|
+
get sectionRangeLabel() {
|
|
1091
|
+
const template = this.constants?.upcomingSection?.paginator?.rangeTemplate ??
|
|
1092
|
+
'{start}-{end} of {total} Meetings & Events';
|
|
1093
|
+
return template
|
|
1094
|
+
.replace('{start}', `${this.sectionRangeStart}`)
|
|
1095
|
+
.replace('{end}', `${this.sectionRangeEnd}`)
|
|
1096
|
+
.replace('{total}', `${this.totalItems}`);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Handles the section paginator change, updating the current section page.
|
|
1100
|
+
* @param {PageEvent} event - The Material paginator page event.
|
|
1101
|
+
* @return {void}
|
|
1102
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1103
|
+
*/
|
|
1104
|
+
onSectionPageChange(event) {
|
|
1105
|
+
this.sectionPageIndex = event.pageIndex;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Allows the host/container to open or close the section (e.g. a "Jump to"
|
|
1109
|
+
* shortcut opens it). Writing the input mirrors the value onto the internal
|
|
1110
|
+
* expand state while leaving the user's own toggle free to change it after.
|
|
1111
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1112
|
+
*/
|
|
1113
|
+
set expanded(value) {
|
|
1114
|
+
this.isExpanded = !!value;
|
|
1115
|
+
}
|
|
1116
|
+
get expanded() {
|
|
1117
|
+
return this.isExpanded;
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* `trackBy` for the event-group-card `*ngFor`, keyed by the stable event id so
|
|
1121
|
+
* Angular renders exactly one card per event in input order (Req 5.5, 5.6, 14.4).
|
|
1122
|
+
* @param {number} index - The iteration index (fallback key).
|
|
1123
|
+
* @param {UpcomingEvent} event - The event for this card.
|
|
1124
|
+
* @return {string} The stable track key (event id).
|
|
1125
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1126
|
+
*/
|
|
1127
|
+
trackByEventId(index, event) {
|
|
1128
|
+
return event?.eventId ?? `${index}`;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Toggles the section's expanded/collapsed state, inverting the card-list
|
|
1132
|
+
* visibility and the exposed `aria-expanded` value (Req 5.4, 14.3).
|
|
1133
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1134
|
+
*/
|
|
1135
|
+
onToggleExpanded() {
|
|
1136
|
+
this.isExpanded = !this.isExpanded;
|
|
1137
|
+
this.expandedChange.emit(this.isExpanded);
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Handles the "View All" link, emitting the `viewAll` intent to the host (Req 5.2).
|
|
1141
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1142
|
+
*/
|
|
1143
|
+
onViewAll() {
|
|
1144
|
+
this.viewAll.emit();
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Bubbles a card's "View Event" activation upward (Req 6.4).
|
|
1148
|
+
* @param {string} eventId - The event id emitted by the card.
|
|
1149
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1150
|
+
*/
|
|
1151
|
+
onViewEvent(eventId) {
|
|
1152
|
+
this.viewEvent.emit(eventId);
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Bubbles a card's meeting-name link activation upward (Req 7.4).
|
|
1156
|
+
* @param {string} meetingId - The meeting id emitted by the card.
|
|
1157
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1158
|
+
*/
|
|
1159
|
+
onOpenMeeting(meetingId) {
|
|
1160
|
+
this.openMeeting.emit(meetingId);
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Bubbles a card's log-attendance request upward (Req 7.7).
|
|
1164
|
+
* @param {string} meetingId - The meeting id emitted by the card.
|
|
1165
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1166
|
+
*/
|
|
1167
|
+
onLogAttendance(meetingId) {
|
|
1168
|
+
this.logAttendance.emit(meetingId);
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Bubbles a card's leave-meeting request upward (Req 7.8).
|
|
1172
|
+
* @param {string} meetingId - The meeting id emitted by the card.
|
|
1173
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1174
|
+
*/
|
|
1175
|
+
onLeaveMeeting(meetingId) {
|
|
1176
|
+
this.leaveMeeting.emit(meetingId);
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Maps a card's `pageChange` into a `meetingPageChange` tagged with the
|
|
1180
|
+
* originating event id so the host can page the correct event (Req 6.9).
|
|
1181
|
+
* @param {string} eventId - The id of the event whose card paginated.
|
|
1182
|
+
* @param {PageChange} page - The requested page from the card paginator.
|
|
1183
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1184
|
+
*/
|
|
1185
|
+
onMeetingPageChange(eventId, page) {
|
|
1186
|
+
this.meetingPageChange.emit({ eventId, ...page });
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Bubbles a card's lazy child-meeting load request upward, tagged with the
|
|
1190
|
+
* originating event id so the container can fetch that event's meetings.
|
|
1191
|
+
* @param {string} eventId - The event whose meetings to load.
|
|
1192
|
+
* @param {number} page - The one-based page requested by the card.
|
|
1193
|
+
* @memberof UpcomingMeetingsEventsComponent
|
|
1194
|
+
*/
|
|
1195
|
+
onLoadEventMeetings(eventId, page) {
|
|
1196
|
+
this.loadEventMeetings.emit({ eventId, page });
|
|
1197
|
+
}
|
|
1198
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UpcomingMeetingsEventsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1199
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: UpcomingMeetingsEventsComponent, isStandalone: true, selector: "ieeesa-upcoming-meetings-events", inputs: { events: "events", sectionState: "sectionState", permissions: "permissions", attendanceStates: "attendanceStates", inFlightMeetingIds: "inFlightMeetingIds", isMobileView: "isMobileView", expanded: "expanded" }, outputs: { viewAll: "viewAll", viewEvent: "viewEvent", openMeeting: "openMeeting", logAttendance: "logAttendance", leaveMeeting: "leaveMeeting", meetingPageChange: "meetingPageChange", loadEventMeetings: "loadEventMeetings", expandedChange: "expandedChange" }, ngImport: i0, template: "<section\r\n class=\"ieeesa-upcoming-meetings-events\"\r\n [class.ieeesa-upcoming-meetings-events--mobile]=\"isMobileView\"\r\n>\r\n <header class=\"ieeesa-upcoming-meetings-events__header\">\r\n <!-- Section title (Req 5.1). -->\r\n <div class=\"ieeesa-upcoming-meetings-events__heading\">\r\n <h2 class=\"ieeesa-upcoming-meetings-events__title\">\r\n {{ constants.upcomingSection.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- View All link + Expand/Collapse toggle (Req 5.1, 5.2, 5.3, 5.4, 14.3). -->\r\n <div class=\"ieeesa-upcoming-meetings-events__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-upcoming-meetings-events__view-all\"\r\n [attr.aria-label]=\"constants.upcomingSection.ariaLabel.viewAll\"\r\n (click)=\"onViewAll()\"\r\n >\r\n {{ constants.upcomingSection.viewAllLabel }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-upcoming-meetings-events__toggle\"\r\n [attr.aria-expanded]=\"isExpanded\"\r\n [attr.aria-label]=\"constants.upcomingSection.ariaLabel.toggle\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <span>{{ isExpanded ? constants.upcomingSection.collapseLabel : constants.upcomingSection.expandLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <!-- Card list, shown only while expanded (Req 5.4). -->\r\n <div *ngIf=\"isExpanded\" class=\"ieeesa-upcoming-meetings-events__body\">\r\n <!-- Loader region (Req 13.1). -->\r\n <div\r\n *ngIf=\"sectionState === sectionStates.LOADING\"\r\n class=\"ieeesa-upcoming-meetings-events__loader\"\r\n >\r\n <ieeesa-loader></ieeesa-loader>\r\n </div>\r\n\r\n <!-- Content region: one card per event preserving input order (Req 5.5, 5.6, 13.2). -->\r\n <div\r\n *ngIf=\"sectionState === sectionStates.LOADED\"\r\n class=\"ieeesa-upcoming-meetings-events__cards\"\r\n >\r\n <ieeesa-event-group-card\r\n *ngFor=\"let event of pagedEvents; trackBy: trackByEventId\"\r\n [event]=\"event\"\r\n [permissions]=\"permissions\"\r\n [attendanceStates]=\"attendanceStates\"\r\n [inFlightMeetingIds]=\"inFlightMeetingIds\"\r\n [isMobileView]=\"isMobileView\"\r\n (viewEvent)=\"onViewEvent($event)\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n (pageChange)=\"onMeetingPageChange(event.eventId, $event)\"\r\n (loadMeetings)=\"onLoadEventMeetings(event.eventId, $event)\"\r\n ></ieeesa-event-group-card>\r\n\r\n <!-- Section-level paginator: 5 events/meetings per page (Req 3.x, design). -->\r\n <div\r\n *ngIf=\"totalItems > sectionPageSize\"\r\n class=\"ieeesa-upcoming-meetings-events__paginator\"\r\n >\r\n <span class=\"ieeesa-upcoming-meetings-events__paginator-range\">\r\n {{ sectionRangeLabel }}\r\n </span>\r\n <mat-paginator\r\n class=\"ieeesa-upcoming-meetings-events__paginator-control\"\r\n [pageIndex]=\"sectionPageIndex\"\r\n [pageSize]=\"sectionPageSize\"\r\n [length]=\"totalItems\"\r\n [hidePageSize]=\"true\"\r\n (page)=\"onSectionPageChange($event)\"\r\n ></mat-paginator>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty-state region (Req 13.3). -->\r\n <p\r\n *ngIf=\"sectionState === sectionStates.EMPTY\"\r\n class=\"ieeesa-upcoming-meetings-events__empty\"\r\n >\r\n {{ constants.upcomingSection.emptyMessage }}\r\n </p>\r\n\r\n <!-- Error region (Req 13.5). -->\r\n <p\r\n *ngIf=\"sectionState === sectionStates.ERROR\"\r\n class=\"ieeesa-upcoming-meetings-events__error\"\r\n role=\"alert\"\r\n >\r\n {{ constants.upcomingSection.errorMessage }}\r\n </p>\r\n </div>\r\n</section>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-upcoming-meetings-events{display:flex;flex-direction:column;gap:16px;background-color:#fff;border-radius:12px;box-shadow:0 1px 2px #0003;border:1px solid #e2e8f0;padding:20px 24px}.ieeesa-upcoming-meetings-events__header{display:flex;align-items:center;justify-content:space-between;gap:16px}.ieeesa-upcoming-meetings-events__heading{display:flex;min-width:0}.ieeesa-upcoming-meetings-events__title{margin:0;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#0f172a}.ieeesa-upcoming-meetings-events__actions{display:flex;align-items:center;gap:16px}.ieeesa-upcoming-meetings-events__view-all{flex-shrink:0;background:none;border:none;padding:0;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-upcoming-meetings-events__view-all:hover{text-decoration:underline}.ieeesa-upcoming-meetings-events__toggle{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border:1px solid #dbe2eb;border-radius:8px;background-color:#fff;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-upcoming-meetings-events__toggle:hover{border-color:#00629b}.ieeesa-upcoming-meetings-events__toggle i{font-size:.75rem}.ieeesa-upcoming-meetings-events__body{display:flex;flex-direction:column}.ieeesa-upcoming-meetings-events__loader{display:flex;align-items:center;justify-content:center;padding:24px}.ieeesa-upcoming-meetings-events__cards{display:flex;flex-direction:column;gap:16px}.ieeesa-upcoming-meetings-events__paginator{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding-top:8px}.ieeesa-upcoming-meetings-events__paginator-range{font-size:.8125rem;color:#939094}.ieeesa-upcoming-meetings-events__empty,.ieeesa-upcoming-meetings-events__error{margin:0;padding:16px;font-size:.875rem;color:#939094}.ieeesa-upcoming-meetings-events__error{color:#ba0c2f}.ieeesa-upcoming-meetings-events--mobile .ieeesa-upcoming-meetings-events__header{flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i2.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: LoaderComponent, selector: "ieeesa-loader", inputs: ["diameter"] }, { kind: "component", type: EventGroupCardComponent, selector: "ieeesa-event-group-card", inputs: ["event", "permissions", "attendanceStates", "inFlightMeetingIds", "isMobileView"], outputs: ["viewEvent", "openMeeting", "logAttendance", "leaveMeeting", "pageChange", "loadMeetings"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1200
|
+
}
|
|
1201
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UpcomingMeetingsEventsComponent, decorators: [{
|
|
1202
|
+
type: Component,
|
|
1203
|
+
args: [{ selector: 'ieeesa-upcoming-meetings-events', standalone: true, imports: [
|
|
1204
|
+
CommonModule,
|
|
1205
|
+
MatPaginatorModule,
|
|
1206
|
+
LoaderComponent,
|
|
1207
|
+
EventGroupCardComponent,
|
|
1208
|
+
], encapsulation: ViewEncapsulation.None, template: "<section\r\n class=\"ieeesa-upcoming-meetings-events\"\r\n [class.ieeesa-upcoming-meetings-events--mobile]=\"isMobileView\"\r\n>\r\n <header class=\"ieeesa-upcoming-meetings-events__header\">\r\n <!-- Section title (Req 5.1). -->\r\n <div class=\"ieeesa-upcoming-meetings-events__heading\">\r\n <h2 class=\"ieeesa-upcoming-meetings-events__title\">\r\n {{ constants.upcomingSection.title }}\r\n </h2>\r\n </div>\r\n\r\n <!-- View All link + Expand/Collapse toggle (Req 5.1, 5.2, 5.3, 5.4, 14.3). -->\r\n <div class=\"ieeesa-upcoming-meetings-events__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-upcoming-meetings-events__view-all\"\r\n [attr.aria-label]=\"constants.upcomingSection.ariaLabel.viewAll\"\r\n (click)=\"onViewAll()\"\r\n >\r\n {{ constants.upcomingSection.viewAllLabel }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-upcoming-meetings-events__toggle\"\r\n [attr.aria-expanded]=\"isExpanded\"\r\n [attr.aria-label]=\"constants.upcomingSection.ariaLabel.toggle\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <span>{{ isExpanded ? constants.upcomingSection.collapseLabel : constants.upcomingSection.expandLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <!-- Card list, shown only while expanded (Req 5.4). -->\r\n <div *ngIf=\"isExpanded\" class=\"ieeesa-upcoming-meetings-events__body\">\r\n <!-- Loader region (Req 13.1). -->\r\n <div\r\n *ngIf=\"sectionState === sectionStates.LOADING\"\r\n class=\"ieeesa-upcoming-meetings-events__loader\"\r\n >\r\n <ieeesa-loader></ieeesa-loader>\r\n </div>\r\n\r\n <!-- Content region: one card per event preserving input order (Req 5.5, 5.6, 13.2). -->\r\n <div\r\n *ngIf=\"sectionState === sectionStates.LOADED\"\r\n class=\"ieeesa-upcoming-meetings-events__cards\"\r\n >\r\n <ieeesa-event-group-card\r\n *ngFor=\"let event of pagedEvents; trackBy: trackByEventId\"\r\n [event]=\"event\"\r\n [permissions]=\"permissions\"\r\n [attendanceStates]=\"attendanceStates\"\r\n [inFlightMeetingIds]=\"inFlightMeetingIds\"\r\n [isMobileView]=\"isMobileView\"\r\n (viewEvent)=\"onViewEvent($event)\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n (pageChange)=\"onMeetingPageChange(event.eventId, $event)\"\r\n (loadMeetings)=\"onLoadEventMeetings(event.eventId, $event)\"\r\n ></ieeesa-event-group-card>\r\n\r\n <!-- Section-level paginator: 5 events/meetings per page (Req 3.x, design). -->\r\n <div\r\n *ngIf=\"totalItems > sectionPageSize\"\r\n class=\"ieeesa-upcoming-meetings-events__paginator\"\r\n >\r\n <span class=\"ieeesa-upcoming-meetings-events__paginator-range\">\r\n {{ sectionRangeLabel }}\r\n </span>\r\n <mat-paginator\r\n class=\"ieeesa-upcoming-meetings-events__paginator-control\"\r\n [pageIndex]=\"sectionPageIndex\"\r\n [pageSize]=\"sectionPageSize\"\r\n [length]=\"totalItems\"\r\n [hidePageSize]=\"true\"\r\n (page)=\"onSectionPageChange($event)\"\r\n ></mat-paginator>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty-state region (Req 13.3). -->\r\n <p\r\n *ngIf=\"sectionState === sectionStates.EMPTY\"\r\n class=\"ieeesa-upcoming-meetings-events__empty\"\r\n >\r\n {{ constants.upcomingSection.emptyMessage }}\r\n </p>\r\n\r\n <!-- Error region (Req 13.5). -->\r\n <p\r\n *ngIf=\"sectionState === sectionStates.ERROR\"\r\n class=\"ieeesa-upcoming-meetings-events__error\"\r\n role=\"alert\"\r\n >\r\n {{ constants.upcomingSection.errorMessage }}\r\n </p>\r\n </div>\r\n</section>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-upcoming-meetings-events{display:flex;flex-direction:column;gap:16px;background-color:#fff;border-radius:12px;box-shadow:0 1px 2px #0003;border:1px solid #e2e8f0;padding:20px 24px}.ieeesa-upcoming-meetings-events__header{display:flex;align-items:center;justify-content:space-between;gap:16px}.ieeesa-upcoming-meetings-events__heading{display:flex;min-width:0}.ieeesa-upcoming-meetings-events__title{margin:0;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#0f172a}.ieeesa-upcoming-meetings-events__actions{display:flex;align-items:center;gap:16px}.ieeesa-upcoming-meetings-events__view-all{flex-shrink:0;background:none;border:none;padding:0;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-upcoming-meetings-events__view-all:hover{text-decoration:underline}.ieeesa-upcoming-meetings-events__toggle{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border:1px solid #dbe2eb;border-radius:8px;background-color:#fff;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-upcoming-meetings-events__toggle:hover{border-color:#00629b}.ieeesa-upcoming-meetings-events__toggle i{font-size:.75rem}.ieeesa-upcoming-meetings-events__body{display:flex;flex-direction:column}.ieeesa-upcoming-meetings-events__loader{display:flex;align-items:center;justify-content:center;padding:24px}.ieeesa-upcoming-meetings-events__cards{display:flex;flex-direction:column;gap:16px}.ieeesa-upcoming-meetings-events__paginator{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding-top:8px}.ieeesa-upcoming-meetings-events__paginator-range{font-size:.8125rem;color:#939094}.ieeesa-upcoming-meetings-events__empty,.ieeesa-upcoming-meetings-events__error{margin:0;padding:16px;font-size:.875rem;color:#939094}.ieeesa-upcoming-meetings-events__error{color:#ba0c2f}.ieeesa-upcoming-meetings-events--mobile .ieeesa-upcoming-meetings-events__header{flex-wrap:wrap}\n"] }]
|
|
1209
|
+
}], propDecorators: { events: [{
|
|
1210
|
+
type: Input
|
|
1211
|
+
}], sectionState: [{
|
|
1212
|
+
type: Input
|
|
1213
|
+
}], permissions: [{
|
|
1214
|
+
type: Input
|
|
1215
|
+
}], attendanceStates: [{
|
|
1216
|
+
type: Input
|
|
1217
|
+
}], inFlightMeetingIds: [{
|
|
1218
|
+
type: Input
|
|
1219
|
+
}], isMobileView: [{
|
|
1220
|
+
type: Input
|
|
1221
|
+
}], viewAll: [{
|
|
1222
|
+
type: Output
|
|
1223
|
+
}], viewEvent: [{
|
|
1224
|
+
type: Output
|
|
1225
|
+
}], openMeeting: [{
|
|
1226
|
+
type: Output
|
|
1227
|
+
}], logAttendance: [{
|
|
1228
|
+
type: Output
|
|
1229
|
+
}], leaveMeeting: [{
|
|
1230
|
+
type: Output
|
|
1231
|
+
}], meetingPageChange: [{
|
|
1232
|
+
type: Output
|
|
1233
|
+
}], loadEventMeetings: [{
|
|
1234
|
+
type: Output
|
|
1235
|
+
}], expanded: [{
|
|
1236
|
+
type: Input
|
|
1237
|
+
}], expandedChange: [{
|
|
1238
|
+
type: Output
|
|
1239
|
+
}] } });
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Identifies which dashboard section a "Jump to" shortcut targets, emitted via
|
|
1243
|
+
* {@link DashboardWelcomeHeaderComponent.shortcutSelected} for the host/container
|
|
1244
|
+
* to scroll to or navigate.
|
|
1245
|
+
*/
|
|
1246
|
+
// eslint-disable-next-line no-unused-vars
|
|
1247
|
+
var DashboardJumpTarget;
|
|
1248
|
+
(function (DashboardJumpTarget) {
|
|
1249
|
+
// eslint-disable-next-line no-unused-vars
|
|
1250
|
+
DashboardJumpTarget["MEETINGS"] = "MEETINGS";
|
|
1251
|
+
// eslint-disable-next-line no-unused-vars
|
|
1252
|
+
DashboardJumpTarget["GROUPS"] = "GROUPS";
|
|
1253
|
+
})(DashboardJumpTarget || (DashboardJumpTarget = {}));
|
|
1254
|
+
/**
|
|
1255
|
+
* Welcome_Header renders the personalized greeting and the "Jump to" shortcut
|
|
1256
|
+
* control at the top of the dashboard.
|
|
1257
|
+
*
|
|
1258
|
+
* The greeting is composed from the greeting label in `constants.json` and the
|
|
1259
|
+
* supplied `userName`, falling back to the configured fallback greeting when the
|
|
1260
|
+
* name is empty or undefined. The "Jump to" control shows one circular icon per
|
|
1261
|
+
* dashboard section (Upcoming Meetings & Events, Your Groups); hovering or
|
|
1262
|
+
* focusing an icon expands it into a pill with the section label and a count
|
|
1263
|
+
* badge (the counts are supplied by the host via `meetingsCount` /
|
|
1264
|
+
* `groupsCount`). Activating a shortcut emits {@link shortcutSelected} with the
|
|
1265
|
+
* target section for the host to act on. Purely presentational — no API work.
|
|
1266
|
+
* @export
|
|
1267
|
+
* @class DashboardWelcomeHeaderComponent
|
|
1268
|
+
*/
|
|
1269
|
+
class DashboardWelcomeHeaderComponent {
|
|
1270
|
+
constructor() {
|
|
1271
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1272
|
+
this.constants = constants$1;
|
|
1273
|
+
/** User-facing strings sourced from `constants.json`. */
|
|
1274
|
+
this.texts = this.constants?.welcomeHeader;
|
|
1275
|
+
/** Enum reference for template comparisons. */
|
|
1276
|
+
this.jumpTarget = DashboardJumpTarget;
|
|
1277
|
+
this.userNameValue = '';
|
|
1278
|
+
this.meetingsCountValue = 0;
|
|
1279
|
+
this.groupsCountValue = 0;
|
|
1280
|
+
/** Emits the selected "Jump to" target for the host to act on. */
|
|
1281
|
+
this.shortcutSelected = new EventEmitter();
|
|
1282
|
+
/** The jump shortcuts rendered in the control, rebuilt when counts change. */
|
|
1283
|
+
this.shortcuts = this.buildShortcutList();
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* The signed-in user's display name. Drives the personalized greeting; when
|
|
1287
|
+
* empty or undefined the greeting falls back to the configured fallback text.
|
|
1288
|
+
* @memberof DashboardWelcomeHeaderComponent
|
|
1289
|
+
*/
|
|
1290
|
+
set userName(value) {
|
|
1291
|
+
this.userNameValue = value ?? '';
|
|
1292
|
+
}
|
|
1293
|
+
get userName() {
|
|
1294
|
+
return this.userNameValue;
|
|
1295
|
+
}
|
|
1296
|
+
/** Count shown in the Upcoming Meetings & Events shortcut badge. */
|
|
1297
|
+
set meetingsCount(value) {
|
|
1298
|
+
this.meetingsCountValue = value ?? 0;
|
|
1299
|
+
this.buildShortcuts();
|
|
1300
|
+
}
|
|
1301
|
+
get meetingsCount() {
|
|
1302
|
+
return this.meetingsCountValue;
|
|
1303
|
+
}
|
|
1304
|
+
/** Count shown in the Your Groups shortcut badge. */
|
|
1305
|
+
set groupsCount(value) {
|
|
1306
|
+
this.groupsCountValue = value ?? 0;
|
|
1307
|
+
this.buildShortcuts();
|
|
1308
|
+
}
|
|
1309
|
+
get groupsCount() {
|
|
1310
|
+
return this.groupsCountValue;
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* The personalized greeting: the greeting label plus the user's name when
|
|
1314
|
+
* present, otherwise the configured fallback greeting.
|
|
1315
|
+
* @readonly
|
|
1316
|
+
* @memberof DashboardWelcomeHeaderComponent
|
|
1317
|
+
*/
|
|
1318
|
+
get greeting() {
|
|
1319
|
+
const name = this.userName?.trim();
|
|
1320
|
+
return name
|
|
1321
|
+
? `${this.texts?.greeting}${name}!`
|
|
1322
|
+
: `${this.texts?.fallbackGreeting}!`;
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Emits the chosen shortcut's target for the host to scroll/navigate to.
|
|
1326
|
+
* @param {DashboardJumpTarget} target - The selected section.
|
|
1327
|
+
* @memberof DashboardWelcomeHeaderComponent
|
|
1328
|
+
*/
|
|
1329
|
+
onShortcutClick(target) {
|
|
1330
|
+
this.shortcutSelected.emit(target);
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* TrackBy for the shortcut list.
|
|
1334
|
+
* @param {number} _index
|
|
1335
|
+
* @param {JumpShortcut} shortcut
|
|
1336
|
+
* @return {string}
|
|
1337
|
+
* @memberof DashboardWelcomeHeaderComponent
|
|
1338
|
+
*/
|
|
1339
|
+
trackByTarget(_index, shortcut) {
|
|
1340
|
+
return shortcut.target;
|
|
1341
|
+
}
|
|
1342
|
+
/** Rebuilds the shortcut list so the template reflects the latest counts. */
|
|
1343
|
+
buildShortcuts() {
|
|
1344
|
+
this.shortcuts = this.buildShortcutList();
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Builds the shortcut view models from `constants.json` and the current
|
|
1348
|
+
* counts.
|
|
1349
|
+
* @return {JumpShortcut[]}
|
|
1350
|
+
* @memberof DashboardWelcomeHeaderComponent
|
|
1351
|
+
*/
|
|
1352
|
+
buildShortcutList() {
|
|
1353
|
+
const shortcutTexts = this.constants?.welcomeHeader?.shortcuts;
|
|
1354
|
+
return [
|
|
1355
|
+
{
|
|
1356
|
+
target: DashboardJumpTarget.MEETINGS,
|
|
1357
|
+
label: shortcutTexts?.meetings?.label,
|
|
1358
|
+
iconUrl: shortcutTexts?.meetings?.iconUrl,
|
|
1359
|
+
ariaLabel: shortcutTexts?.meetings?.ariaLabel,
|
|
1360
|
+
count: this.meetingsCountValue,
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
target: DashboardJumpTarget.GROUPS,
|
|
1364
|
+
label: shortcutTexts?.groups?.label,
|
|
1365
|
+
iconUrl: shortcutTexts?.groups?.iconUrl,
|
|
1366
|
+
ariaLabel: shortcutTexts?.groups?.ariaLabel,
|
|
1367
|
+
count: this.groupsCountValue,
|
|
1368
|
+
},
|
|
1369
|
+
];
|
|
1370
|
+
}
|
|
1371
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardWelcomeHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1372
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DashboardWelcomeHeaderComponent, isStandalone: true, selector: "ieeesa-dashboard-welcome-header", inputs: { userName: "userName", meetingsCount: "meetingsCount", groupsCount: "groupsCount" }, outputs: { shortcutSelected: "shortcutSelected" }, ngImport: i0, template: "<div class=\"ieeesa-dashboard-welcome-header\">\r\n <!-- Greeting + helper line -->\r\n <div class=\"ieeesa-dashboard-welcome-header__intro\">\r\n <h1 class=\"ieeesa-dashboard-welcome-header__greeting m-0\">\r\n {{ greeting }}\r\n </h1>\r\n <p class=\"ieeesa-dashboard-welcome-header__helper-text m-0\">\r\n {{ texts?.helperText }}\r\n </p>\r\n </div>\r\n\r\n <!-- \"Jump to\" shortcuts: each icon expands on hover/focus into a pill with\r\n the section label and its count badge. -->\r\n <div class=\"ieeesa-dashboard-welcome-header__jump-to\">\r\n <span class=\"ieeesa-dashboard-welcome-header__jump-to-label\">\r\n {{ texts?.jumpToLabel }}\r\n </span>\r\n\r\n <button\r\n *ngFor=\"let shortcut of shortcuts; trackBy: trackByTarget\"\r\n type=\"button\"\r\n class=\"ieeesa-dashboard-welcome-header__shortcut\"\r\n [attr.aria-label]=\"shortcut.ariaLabel + ' (' + shortcut.count + ')'\"\r\n (click)=\"onShortcutClick(shortcut.target)\"\r\n >\r\n <img\r\n class=\"ieeesa-dashboard-welcome-header__shortcut-icon\"\r\n [src]=\"shortcut.iconUrl\"\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n />\r\n <span class=\"ieeesa-dashboard-welcome-header__shortcut-label\">\r\n {{ shortcut.label }}\r\n </span>\r\n <span class=\"ieeesa-dashboard-welcome-header__shortcut-count\">\r\n {{ shortcut.count }}\r\n </span>\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-dashboard-welcome-header{display:flex;align-items:center;justify-content:flex-start;gap:10%;flex-wrap:wrap}.ieeesa-dashboard-welcome-header__intro{display:flex;flex-direction:column;gap:4px}.ieeesa-dashboard-welcome-header__greeting{font-family:Calibri Bold;font-weight:700;font-style:normal;font-size:18px;line-height:27px;letter-spacing:0px;color:#111}.ieeesa-dashboard-welcome-header__helper-text{font-family:Calibri Regular;font-weight:400;font-style:normal;font-size:12px;line-height:16.5px;letter-spacing:0px;color:#6a7282}.ieeesa-dashboard-welcome-header__jump-to{display:inline-flex;align-items:center;gap:20px;min-width:228px;width:-moz-fit-content;width:fit-content;height:60px;padding-left:18px;padding-right:18px;background-color:#fff;border-radius:10px;box-shadow:0 1px 2px #0003}.ieeesa-dashboard-welcome-header__jump-to-label{font-family:Calibri Bold;font-weight:700;font-size:.8125rem;letter-spacing:.03125em;text-transform:uppercase;color:#333436;white-space:nowrap}.ieeesa-dashboard-welcome-header__shortcut{display:inline-flex;align-items:center;justify-content:center;gap:0;width:40px;height:40px;padding:0;border:1.5px solid #D1D5DC;border-radius:20px;background-color:#fff;color:#00629b;cursor:pointer;overflow:hidden;will-change:width,padding;transition:width .32s cubic-bezier(.22,1,.36,1),padding .32s cubic-bezier(.22,1,.36,1),gap .32s cubic-bezier(.22,1,.36,1),background-color .25s ease,border-color .25s ease,box-shadow .25s ease}.ieeesa-dashboard-welcome-header__shortcut:hover,.ieeesa-dashboard-welcome-header__shortcut:focus-visible{width:auto;gap:8px;padding:0 14px;border-color:#00629b;background-color:#eaf3f9;box-shadow:0 1px 2px #0003;outline:none}.ieeesa-dashboard-welcome-header__shortcut-icon{flex:0 0 auto;width:20px;height:20px;display:block}.ieeesa-dashboard-welcome-header__shortcut-label{max-width:0;opacity:0;overflow:hidden;white-space:nowrap;font-family:Calibri Bold;font-weight:700;font-size:.875rem;color:#333436;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .18s ease}.ieeesa-dashboard-welcome-header__shortcut-count{display:inline-flex;align-items:center;justify-content:center;max-width:0;padding:0;opacity:0;overflow:hidden;border-radius:12px;background-color:#eaf3f9;color:#00629b;font-family:Calibri Bold;font-weight:700;font-size:.75rem;white-space:nowrap;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .18s ease,padding .2s ease}.ieeesa-dashboard-welcome-header__shortcut:hover .ieeesa-dashboard-welcome-header__shortcut-label,.ieeesa-dashboard-welcome-header__shortcut:focus-visible .ieeesa-dashboard-welcome-header__shortcut-label{max-width:240px;opacity:1;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .22s ease .1s}.ieeesa-dashboard-welcome-header__shortcut:hover .ieeesa-dashboard-welcome-header__shortcut-count,.ieeesa-dashboard-welcome-header__shortcut:focus-visible .ieeesa-dashboard-welcome-header__shortcut-count{max-width:48px;padding:2px 10px;opacity:1;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .22s ease .14s,padding .2s ease}@media (max-width: 767px){.ieeesa-dashboard-welcome-header{align-items:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1373
|
+
}
|
|
1374
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardWelcomeHeaderComponent, decorators: [{
|
|
1375
|
+
type: Component,
|
|
1376
|
+
args: [{ selector: 'ieeesa-dashboard-welcome-header', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<div class=\"ieeesa-dashboard-welcome-header\">\r\n <!-- Greeting + helper line -->\r\n <div class=\"ieeesa-dashboard-welcome-header__intro\">\r\n <h1 class=\"ieeesa-dashboard-welcome-header__greeting m-0\">\r\n {{ greeting }}\r\n </h1>\r\n <p class=\"ieeesa-dashboard-welcome-header__helper-text m-0\">\r\n {{ texts?.helperText }}\r\n </p>\r\n </div>\r\n\r\n <!-- \"Jump to\" shortcuts: each icon expands on hover/focus into a pill with\r\n the section label and its count badge. -->\r\n <div class=\"ieeesa-dashboard-welcome-header__jump-to\">\r\n <span class=\"ieeesa-dashboard-welcome-header__jump-to-label\">\r\n {{ texts?.jumpToLabel }}\r\n </span>\r\n\r\n <button\r\n *ngFor=\"let shortcut of shortcuts; trackBy: trackByTarget\"\r\n type=\"button\"\r\n class=\"ieeesa-dashboard-welcome-header__shortcut\"\r\n [attr.aria-label]=\"shortcut.ariaLabel + ' (' + shortcut.count + ')'\"\r\n (click)=\"onShortcutClick(shortcut.target)\"\r\n >\r\n <img\r\n class=\"ieeesa-dashboard-welcome-header__shortcut-icon\"\r\n [src]=\"shortcut.iconUrl\"\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n />\r\n <span class=\"ieeesa-dashboard-welcome-header__shortcut-label\">\r\n {{ shortcut.label }}\r\n </span>\r\n <span class=\"ieeesa-dashboard-welcome-header__shortcut-count\">\r\n {{ shortcut.count }}\r\n </span>\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-dashboard-welcome-header{display:flex;align-items:center;justify-content:flex-start;gap:10%;flex-wrap:wrap}.ieeesa-dashboard-welcome-header__intro{display:flex;flex-direction:column;gap:4px}.ieeesa-dashboard-welcome-header__greeting{font-family:Calibri Bold;font-weight:700;font-style:normal;font-size:18px;line-height:27px;letter-spacing:0px;color:#111}.ieeesa-dashboard-welcome-header__helper-text{font-family:Calibri Regular;font-weight:400;font-style:normal;font-size:12px;line-height:16.5px;letter-spacing:0px;color:#6a7282}.ieeesa-dashboard-welcome-header__jump-to{display:inline-flex;align-items:center;gap:20px;min-width:228px;width:-moz-fit-content;width:fit-content;height:60px;padding-left:18px;padding-right:18px;background-color:#fff;border-radius:10px;box-shadow:0 1px 2px #0003}.ieeesa-dashboard-welcome-header__jump-to-label{font-family:Calibri Bold;font-weight:700;font-size:.8125rem;letter-spacing:.03125em;text-transform:uppercase;color:#333436;white-space:nowrap}.ieeesa-dashboard-welcome-header__shortcut{display:inline-flex;align-items:center;justify-content:center;gap:0;width:40px;height:40px;padding:0;border:1.5px solid #D1D5DC;border-radius:20px;background-color:#fff;color:#00629b;cursor:pointer;overflow:hidden;will-change:width,padding;transition:width .32s cubic-bezier(.22,1,.36,1),padding .32s cubic-bezier(.22,1,.36,1),gap .32s cubic-bezier(.22,1,.36,1),background-color .25s ease,border-color .25s ease,box-shadow .25s ease}.ieeesa-dashboard-welcome-header__shortcut:hover,.ieeesa-dashboard-welcome-header__shortcut:focus-visible{width:auto;gap:8px;padding:0 14px;border-color:#00629b;background-color:#eaf3f9;box-shadow:0 1px 2px #0003;outline:none}.ieeesa-dashboard-welcome-header__shortcut-icon{flex:0 0 auto;width:20px;height:20px;display:block}.ieeesa-dashboard-welcome-header__shortcut-label{max-width:0;opacity:0;overflow:hidden;white-space:nowrap;font-family:Calibri Bold;font-weight:700;font-size:.875rem;color:#333436;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .18s ease}.ieeesa-dashboard-welcome-header__shortcut-count{display:inline-flex;align-items:center;justify-content:center;max-width:0;padding:0;opacity:0;overflow:hidden;border-radius:12px;background-color:#eaf3f9;color:#00629b;font-family:Calibri Bold;font-weight:700;font-size:.75rem;white-space:nowrap;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .18s ease,padding .2s ease}.ieeesa-dashboard-welcome-header__shortcut:hover .ieeesa-dashboard-welcome-header__shortcut-label,.ieeesa-dashboard-welcome-header__shortcut:focus-visible .ieeesa-dashboard-welcome-header__shortcut-label{max-width:240px;opacity:1;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .22s ease .1s}.ieeesa-dashboard-welcome-header__shortcut:hover .ieeesa-dashboard-welcome-header__shortcut-count,.ieeesa-dashboard-welcome-header__shortcut:focus-visible .ieeesa-dashboard-welcome-header__shortcut-count{max-width:48px;padding:2px 10px;opacity:1;transition:max-width .32s cubic-bezier(.22,1,.36,1),opacity .22s ease .14s,padding .2s ease}@media (max-width: 767px){.ieeesa-dashboard-welcome-header{align-items:flex-start}}\n"] }]
|
|
1377
|
+
}], propDecorators: { userName: [{
|
|
1378
|
+
type: Input
|
|
1379
|
+
}], meetingsCount: [{
|
|
1380
|
+
type: Input
|
|
1381
|
+
}], groupsCount: [{
|
|
1382
|
+
type: Input
|
|
1383
|
+
}], shortcutSelected: [{
|
|
1384
|
+
type: Output
|
|
1385
|
+
}] } });
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Groups_Section (`ieeesa-your-groups`) renders the signed-in user's groups in
|
|
1389
|
+
* a collapsible card as a custom hierarchy table styled like the My Profile
|
|
1390
|
+
* Find Groups tree: each group row carries a blue +/- toggle (when it has an
|
|
1391
|
+
* ancestor hierarchy) that expands to reveal the group's hierarchy path
|
|
1392
|
+
* (root→leaf), indented. Columns: Group, Type, Officer Role, Affiliation,
|
|
1393
|
+
* Member Level (the member level renders as a coloured pill — green for an
|
|
1394
|
+
* assigned level, amber for "Unassigned"). The card paginates the top-level
|
|
1395
|
+
* groups (5 per page).
|
|
1396
|
+
*
|
|
1397
|
+
* Purely presentational: data arrives via `@Input`, intents leave via
|
|
1398
|
+
* `@Output`; no API or navigation here. States (loader / empty / error / table)
|
|
1399
|
+
* are driven by `sectionState`.
|
|
1400
|
+
* @export
|
|
1401
|
+
* @class YourGroupsComponent
|
|
1402
|
+
*/
|
|
1403
|
+
class YourGroupsComponent {
|
|
1404
|
+
constructor() {
|
|
1405
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1406
|
+
this.constants = constants$1;
|
|
1407
|
+
/** User-facing strings sourced from `constants.json`. */
|
|
1408
|
+
this.texts = this.constants?.groupsSection;
|
|
1409
|
+
/** Enum reference for template comparisons against `sectionState`. */
|
|
1410
|
+
this.sectionStates = DashboardSectionState;
|
|
1411
|
+
/** Per-level indentation step (px) for the expanded hierarchy rows. */
|
|
1412
|
+
this.indentPerLevel = 28;
|
|
1413
|
+
/** Selectable "Items per page" page sizes. */
|
|
1414
|
+
this.pageSizeOptions = [5, 10, 25];
|
|
1415
|
+
this.groupsValue = [];
|
|
1416
|
+
/** The section's load/empty/error state driving the mutually-exclusive regions. */
|
|
1417
|
+
this.sectionState = DashboardSectionState.LOADED;
|
|
1418
|
+
/** Total number of groups (for the "{n} Groups" count and paginator). */
|
|
1419
|
+
this.totalGroups = 0;
|
|
1420
|
+
this.pageIndexValue = 0;
|
|
1421
|
+
this.pageSizeValue = 5;
|
|
1422
|
+
/** Emits when the "View All" link is activated. */
|
|
1423
|
+
this.viewAllGroups = new EventEmitter();
|
|
1424
|
+
/** Emits the requested page when the paginator changes. */
|
|
1425
|
+
this.pageChange = new EventEmitter();
|
|
1426
|
+
/**
|
|
1427
|
+
* Emits the new expanded state whenever the user toggles the card, so a
|
|
1428
|
+
* two-way `[(expanded)]` binding keeps the host's flag in sync. Without this,
|
|
1429
|
+
* a host that opened the card (expanded=true) and then the user collapsing it
|
|
1430
|
+
* would leave the host flag stale, so re-opening via the same input value
|
|
1431
|
+
* would be a no-op.
|
|
1432
|
+
* @memberof YourGroupsComponent
|
|
1433
|
+
*/
|
|
1434
|
+
this.expandedChange = new EventEmitter();
|
|
1435
|
+
/** Whether the card is expanded (table visible). Starts collapsed. */
|
|
1436
|
+
this.isExpanded = false;
|
|
1437
|
+
/** GroupIds of the top-level groups whose hierarchy is currently expanded. */
|
|
1438
|
+
this.expandedGroupIds = new Set();
|
|
1439
|
+
/** The flattened rows currently rendered (group rows + any expanded hierarchy rows). */
|
|
1440
|
+
this.visibleRows = [];
|
|
1441
|
+
}
|
|
1442
|
+
/** The groups rendered in the table. */
|
|
1443
|
+
set groups(value) {
|
|
1444
|
+
this.groupsValue = value ?? [];
|
|
1445
|
+
this.rebuildRows();
|
|
1446
|
+
}
|
|
1447
|
+
get groups() {
|
|
1448
|
+
return this.groupsValue;
|
|
1449
|
+
}
|
|
1450
|
+
/** Current zero-based page index. */
|
|
1451
|
+
set pageIndex(value) {
|
|
1452
|
+
this.pageIndexValue = value ?? 0;
|
|
1453
|
+
this.rebuildRows();
|
|
1454
|
+
}
|
|
1455
|
+
get pageIndex() {
|
|
1456
|
+
return this.pageIndexValue;
|
|
1457
|
+
}
|
|
1458
|
+
/** Current page size (defaults to 5 rows per page per the design). */
|
|
1459
|
+
set pageSize(value) {
|
|
1460
|
+
this.pageSizeValue = value ?? 5;
|
|
1461
|
+
this.rebuildRows();
|
|
1462
|
+
}
|
|
1463
|
+
get pageSize() {
|
|
1464
|
+
return this.pageSizeValue;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Allows the host/container to open or close the card (e.g. a "Jump to"
|
|
1468
|
+
* shortcut opens it).
|
|
1469
|
+
* @memberof YourGroupsComponent
|
|
1470
|
+
*/
|
|
1471
|
+
set expanded(value) {
|
|
1472
|
+
this.isExpanded = !!value;
|
|
1473
|
+
}
|
|
1474
|
+
get expanded() {
|
|
1475
|
+
return this.isExpanded;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* The count shown in the header subtitle — the server total when provided,
|
|
1479
|
+
* otherwise the number of groups.
|
|
1480
|
+
* @readonly
|
|
1481
|
+
* @memberof YourGroupsComponent
|
|
1482
|
+
*/
|
|
1483
|
+
get groupCount() {
|
|
1484
|
+
return this.totalGroups || this.groups.length || 0;
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Whether a group row can expand: it has an ancestor hierarchy (more than the
|
|
1488
|
+
* group's own node). A single-node hierarchy (the group itself) is a leaf.
|
|
1489
|
+
* @param {GroupRow} group
|
|
1490
|
+
* @return {boolean}
|
|
1491
|
+
* @memberof YourGroupsComponent
|
|
1492
|
+
*/
|
|
1493
|
+
hasHierarchy(group) {
|
|
1494
|
+
return (group?.hierarchy?.length ?? 0) > 1;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Whether the given group row is currently expanded.
|
|
1498
|
+
* @param {GroupRow} group
|
|
1499
|
+
* @return {boolean}
|
|
1500
|
+
* @memberof YourGroupsComponent
|
|
1501
|
+
*/
|
|
1502
|
+
isGroupExpanded(group) {
|
|
1503
|
+
return this.expandedGroupIds.has(group.groupId);
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Toggles a group's hierarchy expansion and rebuilds the visible rows.
|
|
1507
|
+
* @param {GroupRow} group
|
|
1508
|
+
* @memberof YourGroupsComponent
|
|
1509
|
+
*/
|
|
1510
|
+
onToggleHierarchy(group) {
|
|
1511
|
+
if (!this.hasHierarchy(group)) {
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
if (this.expandedGroupIds.has(group.groupId)) {
|
|
1515
|
+
this.expandedGroupIds.delete(group.groupId);
|
|
1516
|
+
}
|
|
1517
|
+
else {
|
|
1518
|
+
this.expandedGroupIds.add(group.groupId);
|
|
1519
|
+
}
|
|
1520
|
+
this.rebuildRows();
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Toggles the card's expanded/collapsed state (whole table visibility) and
|
|
1524
|
+
* emits the new state so the host's two-way binding stays in sync.
|
|
1525
|
+
* @memberof YourGroupsComponent
|
|
1526
|
+
*/
|
|
1527
|
+
onToggleExpand() {
|
|
1528
|
+
this.isExpanded = !this.isExpanded;
|
|
1529
|
+
this.expandedChange.emit(this.isExpanded);
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Emits the "View All" intent for the host.
|
|
1533
|
+
* @memberof YourGroupsComponent
|
|
1534
|
+
*/
|
|
1535
|
+
onViewAll() {
|
|
1536
|
+
this.viewAllGroups.emit();
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Re-emits the Material paginator change (page index or "Items per page"
|
|
1540
|
+
* size) as a {@link PageChange} for the host.
|
|
1541
|
+
* @param {PageEvent} event - The Material paginator event.
|
|
1542
|
+
* @memberof YourGroupsComponent
|
|
1543
|
+
*/
|
|
1544
|
+
onPaginatorChange(event) {
|
|
1545
|
+
this.pageChange.emit({
|
|
1546
|
+
pageIndex: event.pageIndex,
|
|
1547
|
+
pageSize: event.pageSize,
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
/**
|
|
1551
|
+
* Resolves the member-level pill CSS class, mirroring the My Groups profile
|
|
1552
|
+
* tab: an assigned level renders green (success), "Unassigned" renders amber.
|
|
1553
|
+
* @param {string} memberLevel
|
|
1554
|
+
* @return {string}
|
|
1555
|
+
* @memberof YourGroupsComponent
|
|
1556
|
+
*/
|
|
1557
|
+
resolveBadgeClass(memberLevel) {
|
|
1558
|
+
const badge = this.texts?.memberLevelBadge;
|
|
1559
|
+
return memberLevel === this.texts?.unassignedMemberLevel
|
|
1560
|
+
? badge?.warning
|
|
1561
|
+
: badge?.success;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* TrackBy for the rendered table rows.
|
|
1565
|
+
* @param {number} index
|
|
1566
|
+
* @param {TableRow} row
|
|
1567
|
+
* @return {string}
|
|
1568
|
+
* @memberof YourGroupsComponent
|
|
1569
|
+
*/
|
|
1570
|
+
trackByRow(index, row) {
|
|
1571
|
+
return row.kind === 'group'
|
|
1572
|
+
? `g:${row.group?.groupId}`
|
|
1573
|
+
: `h:${row.group?.groupId}:${row.node?.groupId}:${index}`;
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Rebuilds the flat list of visible rows: the current page of top-level group
|
|
1577
|
+
* rows, each optionally followed by its hierarchy (ancestor) rows when the
|
|
1578
|
+
* group is expanded. The hierarchy path is shown root→leaf, indented by depth.
|
|
1579
|
+
* @memberof YourGroupsComponent
|
|
1580
|
+
*/
|
|
1581
|
+
rebuildRows() {
|
|
1582
|
+
const start = this.pageIndex * this.pageSize;
|
|
1583
|
+
const pageGroups = this.groups.slice(start, start + this.pageSize);
|
|
1584
|
+
const rows = [];
|
|
1585
|
+
pageGroups.forEach((group) => {
|
|
1586
|
+
rows.push({ kind: 'group', group, level: 0 });
|
|
1587
|
+
if (this.expandedGroupIds.has(group.groupId)) {
|
|
1588
|
+
(group.hierarchy ?? []).forEach((node, depth) => {
|
|
1589
|
+
rows.push({ kind: 'hierarchy', group, node, level: depth + 1 });
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
this.visibleRows = rows;
|
|
1594
|
+
}
|
|
1595
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: YourGroupsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1596
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: YourGroupsComponent, isStandalone: true, selector: "ieeesa-your-groups", inputs: { groups: "groups", sectionState: "sectionState", totalGroups: "totalGroups", pageIndex: "pageIndex", pageSize: "pageSize", expanded: "expanded" }, outputs: { viewAllGroups: "viewAllGroups", pageChange: "pageChange", expandedChange: "expandedChange" }, ngImport: i0, template: "<section class=\"ieeesa-your-groups\">\r\n <!-- Header: title + count, View All link, collapse/expand toggle -->\r\n <div class=\"ieeesa-your-groups__header\">\r\n <div class=\"ieeesa-your-groups__heading\">\r\n <h2 class=\"ieeesa-your-groups__title m-0\">{{ texts?.title }}</h2>\r\n </div>\r\n\r\n <div class=\"ieeesa-your-groups__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__view-all\"\r\n [attr.aria-label]=\"texts?.ariaLabel?.viewAll\"\r\n (click)=\"onViewAll()\"\r\n >\r\n {{ texts?.viewAllLabel }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__toggle\"\r\n [attr.aria-expanded]=\"isExpanded\"\r\n [attr.aria-label]=\"texts?.ariaLabel?.toggle\"\r\n (click)=\"onToggleExpand()\"\r\n >\r\n <span>{{ isExpanded ? texts?.collapseLabel : texts?.expandLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Body: only when the card is expanded. -->\r\n <div class=\"ieeesa-your-groups__body\" *ngIf=\"isExpanded\">\r\n <ieeesa-loader\r\n *ngIf=\"sectionState === sectionStates.LOADING\"\r\n ></ieeesa-loader>\r\n\r\n <p\r\n *ngIf=\"sectionState === sectionStates.ERROR\"\r\n class=\"ieeesa-your-groups__message ieeesa-your-groups__message--error\"\r\n role=\"alert\"\r\n >\r\n {{ texts?.errorMessage }}\r\n </p>\r\n\r\n <p\r\n *ngIf=\"sectionState === sectionStates.EMPTY\"\r\n class=\"ieeesa-your-groups__message\"\r\n role=\"status\"\r\n >\r\n {{ texts?.emptyMessage }}\r\n </p>\r\n\r\n <ng-container *ngIf=\"sectionState === sectionStates.LOADED\">\r\n <table class=\"ieeesa-your-groups__table\">\r\n <thead>\r\n <tr>\r\n <th scope=\"col\">{{ texts?.columns?.group }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.type }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.officerRole }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.affiliation }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.memberLevel }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of visibleRows; trackBy: trackByRow\">\r\n <!-- GROUP ROW -->\r\n <ng-container *ngIf=\"row.kind === 'group'\">\r\n <td class=\"ieeesa-your-groups__group-cell\">\r\n <!-- Parent: blue +/- toggle to reveal the hierarchy. -->\r\n <button\r\n *ngIf=\"hasHierarchy(row.group!)\"\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [attr.aria-expanded]=\"isGroupExpanded(row.group!)\"\r\n [attr.aria-label]=\"\r\n (isGroupExpanded(row.group!)\r\n ? texts?.collapseLabel\r\n : texts?.expandLabel) +\r\n ' ' +\r\n row.group!.group\r\n \"\r\n (click)=\"onToggleHierarchy(row.group!)\"\r\n >\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isGroupExpanded(row.group!) ? 'fa-minus' : 'fa-plus'\"\r\n ></i>\r\n </button>\r\n <!-- Leaf: spacer keeps names aligned with parents' names. -->\r\n <span\r\n *ngIf=\"!hasHierarchy(row.group!)\"\r\n class=\"ieeesa-your-groups__toggle-spacer\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n <span class=\"ieeesa-your-groups__group-name\">\r\n {{ row.group!.group }}\r\n </span>\r\n </td>\r\n <td>{{ row.group!.type }}</td>\r\n <td>{{ row.group!.officerRole }}</td>\r\n <td>{{ row.group!.affiliation }}</td>\r\n <td>\r\n <span\r\n class=\"ieeesa-your-groups__badge\"\r\n [ngClass]=\"resolveBadgeClass(row.group!.memberLevel)\"\r\n >\r\n {{ row.group!.memberLevel }}\r\n </span>\r\n </td>\r\n </ng-container>\r\n\r\n <!-- HIERARCHY (ancestor) ROW -->\r\n <ng-container *ngIf=\"row.kind === 'hierarchy'\">\r\n <td class=\"ieeesa-your-groups__group-cell ieeesa-your-groups__hierarchy-cell\">\r\n <span\r\n class=\"ieeesa-your-groups__indent\"\r\n [style.width.px]=\"row.level * indentPerLevel\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n <span class=\"ieeesa-your-groups__hierarchy-connector\" aria-hidden=\"true\">\r\n <i class=\"fa-solid fa-turn-up fa-rotate-90\"></i>\r\n </span>\r\n <span class=\"ieeesa-your-groups__hierarchy-name\">\r\n {{ row.node!.groupName }}\r\n <span\r\n *ngIf=\"row.node!.groupAcronym\"\r\n class=\"ieeesa-your-groups__hierarchy-acronym\"\r\n >\r\n ({{ row.node!.groupAcronym }})\r\n </span>\r\n </span>\r\n </td>\r\n <td colspan=\"4\"></td>\r\n </ng-container>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Pagination: the same Angular Material paginator the shared data-table\r\n uses \u2014 it provides the \"Items per page\" dropdown, range label, and\r\n prev/next controls. -->\r\n <mat-paginator\r\n *ngIf=\"groupCount > 0\"\r\n class=\"ieeesa-your-groups__paginator\"\r\n [length]=\"groupCount\"\r\n [pageSize]=\"pageSize\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSizeOptions]=\"pageSizeOptions\"\r\n (page)=\"onPaginatorChange($event)\"\r\n ></mat-paginator>\r\n </ng-container>\r\n </div>\r\n</section>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-your-groups{display:block;background-color:#fff;border-radius:12px;box-shadow:0 1px 2px #0003;padding:20px 24px;border:1px solid #E2E8F0}.ieeesa-your-groups__header{display:flex;align-items:center;justify-content:space-between;gap:16px}.ieeesa-your-groups__heading{display:flex;flex-direction:column;gap:2px}.ieeesa-your-groups__title{font-family:Calibri Bold;font-weight:700;font-size:18px;color:#0f172a}.ieeesa-your-groups__count{font-family:Calibri Regular;font-size:.75rem;color:#777a7e}.ieeesa-your-groups__actions{display:flex;align-items:center;gap:16px}.ieeesa-your-groups__view-all{background:none;border:none;padding:0;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-your-groups__view-all:hover{text-decoration:underline}.ieeesa-your-groups__toggle{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border:1px solid #dbe2eb;border-radius:8px;background-color:#fff;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-your-groups__toggle:hover{border-color:#00629b}.ieeesa-your-groups__toggle i{font-size:.75rem}.ieeesa-your-groups__body{margin-top:16px}.ieeesa-your-groups__message{text-align:center;padding:32px 0;font-family:Calibri Regular;font-size:.875rem;color:#777a7e}.ieeesa-your-groups__message--error{color:#ba0c2f}.ieeesa-your-groups__table{width:100%;border-collapse:collapse}.ieeesa-your-groups__table th,.ieeesa-your-groups__table td{text-align:left;padding:14px 16px;border-bottom:1px solid #dbe2eb;vertical-align:middle}.ieeesa-your-groups__table th{background-color:#f4f5f7;color:#333436;font-family:Calibri Bold;font-weight:700;font-size:.875rem}.ieeesa-your-groups__table td{color:#333436;font-size:.875rem}.ieeesa-your-groups__table tbody tr:nth-child(2n) td{background-color:#f8fcff}.ieeesa-your-groups__group-cell{display:flex;align-items:center;gap:10px}.ieeesa-your-groups__indent{flex:0 0 auto;display:inline-block}.ieeesa-your-groups__hierarchy-toggle{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:4px;background-color:#00629b;color:#fff;font-size:.875rem;line-height:1;cursor:pointer}.ieeesa-your-groups__hierarchy-toggle:hover{background-color:#003e65}.ieeesa-your-groups__toggle-spacer{flex:0 0 auto;display:inline-block;width:24px;height:24px}.ieeesa-your-groups__group-name{color:#00629b;font-family:Calibri Bold;font-weight:700}.ieeesa-your-groups__hierarchy-cell{gap:6px}.ieeesa-your-groups__hierarchy-connector{flex:0 0 auto;display:inline-flex;align-items:center;color:#777a7e}.ieeesa-your-groups__hierarchy-name{color:#333436}.ieeesa-your-groups__hierarchy-acronym{color:#777a7e}.ieeesa-your-groups__badge{display:inline-flex;align-items:center;padding:.125em .75em;border-radius:1em;font-size:.875rem;white-space:nowrap}.ieeesa-your-groups__badge--success{color:#2e7d32;background-color:#2e7d321f}.ieeesa-your-groups__badge--warning{color:#b35600;background-color:#b356001f}.ieeesa-your-groups__paginator{margin-top:8px}.ieeesa-your-groups__paginator ::ng-deep .mat-mdc-paginator-container{justify-content:flex-end}.ieeesa-your-groups__paginator ::ng-deep .mat-mdc-paginator{background-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i2.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: LoaderComponent, selector: "ieeesa-loader", inputs: ["diameter"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1597
|
+
}
|
|
1598
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: YourGroupsComponent, decorators: [{
|
|
1599
|
+
type: Component,
|
|
1600
|
+
args: [{ selector: 'ieeesa-your-groups', standalone: true, imports: [CommonModule, MatPaginatorModule, LoaderComponent], encapsulation: ViewEncapsulation.None, template: "<section class=\"ieeesa-your-groups\">\r\n <!-- Header: title + count, View All link, collapse/expand toggle -->\r\n <div class=\"ieeesa-your-groups__header\">\r\n <div class=\"ieeesa-your-groups__heading\">\r\n <h2 class=\"ieeesa-your-groups__title m-0\">{{ texts?.title }}</h2>\r\n </div>\r\n\r\n <div class=\"ieeesa-your-groups__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__view-all\"\r\n [attr.aria-label]=\"texts?.ariaLabel?.viewAll\"\r\n (click)=\"onViewAll()\"\r\n >\r\n {{ texts?.viewAllLabel }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__toggle\"\r\n [attr.aria-expanded]=\"isExpanded\"\r\n [attr.aria-label]=\"texts?.ariaLabel?.toggle\"\r\n (click)=\"onToggleExpand()\"\r\n >\r\n <span>{{ isExpanded ? texts?.collapseLabel : texts?.expandLabel }}</span>\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"\r\n aria-hidden=\"true\"\r\n ></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Body: only when the card is expanded. -->\r\n <div class=\"ieeesa-your-groups__body\" *ngIf=\"isExpanded\">\r\n <ieeesa-loader\r\n *ngIf=\"sectionState === sectionStates.LOADING\"\r\n ></ieeesa-loader>\r\n\r\n <p\r\n *ngIf=\"sectionState === sectionStates.ERROR\"\r\n class=\"ieeesa-your-groups__message ieeesa-your-groups__message--error\"\r\n role=\"alert\"\r\n >\r\n {{ texts?.errorMessage }}\r\n </p>\r\n\r\n <p\r\n *ngIf=\"sectionState === sectionStates.EMPTY\"\r\n class=\"ieeesa-your-groups__message\"\r\n role=\"status\"\r\n >\r\n {{ texts?.emptyMessage }}\r\n </p>\r\n\r\n <ng-container *ngIf=\"sectionState === sectionStates.LOADED\">\r\n <table class=\"ieeesa-your-groups__table\">\r\n <thead>\r\n <tr>\r\n <th scope=\"col\">{{ texts?.columns?.group }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.type }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.officerRole }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.affiliation }}</th>\r\n <th scope=\"col\">{{ texts?.columns?.memberLevel }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of visibleRows; trackBy: trackByRow\">\r\n <!-- GROUP ROW -->\r\n <ng-container *ngIf=\"row.kind === 'group'\">\r\n <td class=\"ieeesa-your-groups__group-cell\">\r\n <!-- Parent: blue +/- toggle to reveal the hierarchy. -->\r\n <button\r\n *ngIf=\"hasHierarchy(row.group!)\"\r\n type=\"button\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [attr.aria-expanded]=\"isGroupExpanded(row.group!)\"\r\n [attr.aria-label]=\"\r\n (isGroupExpanded(row.group!)\r\n ? texts?.collapseLabel\r\n : texts?.expandLabel) +\r\n ' ' +\r\n row.group!.group\r\n \"\r\n (click)=\"onToggleHierarchy(row.group!)\"\r\n >\r\n <i\r\n class=\"fa-solid\"\r\n [ngClass]=\"isGroupExpanded(row.group!) ? 'fa-minus' : 'fa-plus'\"\r\n ></i>\r\n </button>\r\n <!-- Leaf: spacer keeps names aligned with parents' names. -->\r\n <span\r\n *ngIf=\"!hasHierarchy(row.group!)\"\r\n class=\"ieeesa-your-groups__toggle-spacer\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n <span class=\"ieeesa-your-groups__group-name\">\r\n {{ row.group!.group }}\r\n </span>\r\n </td>\r\n <td>{{ row.group!.type }}</td>\r\n <td>{{ row.group!.officerRole }}</td>\r\n <td>{{ row.group!.affiliation }}</td>\r\n <td>\r\n <span\r\n class=\"ieeesa-your-groups__badge\"\r\n [ngClass]=\"resolveBadgeClass(row.group!.memberLevel)\"\r\n >\r\n {{ row.group!.memberLevel }}\r\n </span>\r\n </td>\r\n </ng-container>\r\n\r\n <!-- HIERARCHY (ancestor) ROW -->\r\n <ng-container *ngIf=\"row.kind === 'hierarchy'\">\r\n <td class=\"ieeesa-your-groups__group-cell ieeesa-your-groups__hierarchy-cell\">\r\n <span\r\n class=\"ieeesa-your-groups__indent\"\r\n [style.width.px]=\"row.level * indentPerLevel\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n <span class=\"ieeesa-your-groups__hierarchy-connector\" aria-hidden=\"true\">\r\n <i class=\"fa-solid fa-turn-up fa-rotate-90\"></i>\r\n </span>\r\n <span class=\"ieeesa-your-groups__hierarchy-name\">\r\n {{ row.node!.groupName }}\r\n <span\r\n *ngIf=\"row.node!.groupAcronym\"\r\n class=\"ieeesa-your-groups__hierarchy-acronym\"\r\n >\r\n ({{ row.node!.groupAcronym }})\r\n </span>\r\n </span>\r\n </td>\r\n <td colspan=\"4\"></td>\r\n </ng-container>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Pagination: the same Angular Material paginator the shared data-table\r\n uses \u2014 it provides the \"Items per page\" dropdown, range label, and\r\n prev/next controls. -->\r\n <mat-paginator\r\n *ngIf=\"groupCount > 0\"\r\n class=\"ieeesa-your-groups__paginator\"\r\n [length]=\"groupCount\"\r\n [pageSize]=\"pageSize\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSizeOptions]=\"pageSizeOptions\"\r\n (page)=\"onPaginatorChange($event)\"\r\n ></mat-paginator>\r\n </ng-container>\r\n </div>\r\n</section>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-your-groups{display:block;background-color:#fff;border-radius:12px;box-shadow:0 1px 2px #0003;padding:20px 24px;border:1px solid #E2E8F0}.ieeesa-your-groups__header{display:flex;align-items:center;justify-content:space-between;gap:16px}.ieeesa-your-groups__heading{display:flex;flex-direction:column;gap:2px}.ieeesa-your-groups__title{font-family:Calibri Bold;font-weight:700;font-size:18px;color:#0f172a}.ieeesa-your-groups__count{font-family:Calibri Regular;font-size:.75rem;color:#777a7e}.ieeesa-your-groups__actions{display:flex;align-items:center;gap:16px}.ieeesa-your-groups__view-all{background:none;border:none;padding:0;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-your-groups__view-all:hover{text-decoration:underline}.ieeesa-your-groups__toggle{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border:1px solid #dbe2eb;border-radius:8px;background-color:#fff;cursor:pointer;font-family:Calibri Bold;font-weight:700;font-size:18px;color:#00629b}.ieeesa-your-groups__toggle:hover{border-color:#00629b}.ieeesa-your-groups__toggle i{font-size:.75rem}.ieeesa-your-groups__body{margin-top:16px}.ieeesa-your-groups__message{text-align:center;padding:32px 0;font-family:Calibri Regular;font-size:.875rem;color:#777a7e}.ieeesa-your-groups__message--error{color:#ba0c2f}.ieeesa-your-groups__table{width:100%;border-collapse:collapse}.ieeesa-your-groups__table th,.ieeesa-your-groups__table td{text-align:left;padding:14px 16px;border-bottom:1px solid #dbe2eb;vertical-align:middle}.ieeesa-your-groups__table th{background-color:#f4f5f7;color:#333436;font-family:Calibri Bold;font-weight:700;font-size:.875rem}.ieeesa-your-groups__table td{color:#333436;font-size:.875rem}.ieeesa-your-groups__table tbody tr:nth-child(2n) td{background-color:#f8fcff}.ieeesa-your-groups__group-cell{display:flex;align-items:center;gap:10px}.ieeesa-your-groups__indent{flex:0 0 auto;display:inline-block}.ieeesa-your-groups__hierarchy-toggle{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:4px;background-color:#00629b;color:#fff;font-size:.875rem;line-height:1;cursor:pointer}.ieeesa-your-groups__hierarchy-toggle:hover{background-color:#003e65}.ieeesa-your-groups__toggle-spacer{flex:0 0 auto;display:inline-block;width:24px;height:24px}.ieeesa-your-groups__group-name{color:#00629b;font-family:Calibri Bold;font-weight:700}.ieeesa-your-groups__hierarchy-cell{gap:6px}.ieeesa-your-groups__hierarchy-connector{flex:0 0 auto;display:inline-flex;align-items:center;color:#777a7e}.ieeesa-your-groups__hierarchy-name{color:#333436}.ieeesa-your-groups__hierarchy-acronym{color:#777a7e}.ieeesa-your-groups__badge{display:inline-flex;align-items:center;padding:.125em .75em;border-radius:1em;font-size:.875rem;white-space:nowrap}.ieeesa-your-groups__badge--success{color:#2e7d32;background-color:#2e7d321f}.ieeesa-your-groups__badge--warning{color:#b35600;background-color:#b356001f}.ieeesa-your-groups__paginator{margin-top:8px}.ieeesa-your-groups__paginator ::ng-deep .mat-mdc-paginator-container{justify-content:flex-end}.ieeesa-your-groups__paginator ::ng-deep .mat-mdc-paginator{background-color:transparent}\n"] }]
|
|
1601
|
+
}], propDecorators: { groups: [{
|
|
1602
|
+
type: Input
|
|
1603
|
+
}], sectionState: [{
|
|
1604
|
+
type: Input
|
|
1605
|
+
}], totalGroups: [{
|
|
1606
|
+
type: Input
|
|
1607
|
+
}], pageIndex: [{
|
|
1608
|
+
type: Input
|
|
1609
|
+
}], pageSize: [{
|
|
1610
|
+
type: Input
|
|
1611
|
+
}], viewAllGroups: [{
|
|
1612
|
+
type: Output
|
|
1613
|
+
}], pageChange: [{
|
|
1614
|
+
type: Output
|
|
1615
|
+
}], expandedChange: [{
|
|
1616
|
+
type: Output
|
|
1617
|
+
}], expanded: [{
|
|
1618
|
+
type: Input
|
|
1619
|
+
}] } });
|
|
1620
|
+
|
|
1621
|
+
/**
|
|
1622
|
+
* Determines whether a raw list item is an EVENT (owns child meetings) or a
|
|
1623
|
+
* STANDALONE_MEETING. An item is an EVENT when the backend flags it with
|
|
1624
|
+
* `isMeetingEvent === true` or `hasChildren === true`.
|
|
1625
|
+
* @param {EventMeetingListItem} item - The raw list item.
|
|
1626
|
+
* @return {UpcomingItemKind} The resolved render kind.
|
|
1627
|
+
*/
|
|
1628
|
+
function resolveItemKind(item) {
|
|
1629
|
+
const isEvent = item?.isMeetingEvent === true || item?.hasChildren === true;
|
|
1630
|
+
return isEvent ? UpcomingItemKind.EVENT : UpcomingItemKind.STANDALONE_MEETING;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Maps a raw backend list item to the {@link UpcomingEvent} view model. EVENT
|
|
1634
|
+
* rows start with an empty `meetings` array (child meetings are lazily loaded on
|
|
1635
|
+
* expand); STANDALONE_MEETING rows carry their own group/location fields.
|
|
1636
|
+
* @param {EventMeetingListItem} item - The raw list item.
|
|
1637
|
+
* @return {UpcomingEvent} The mapped view model.
|
|
1638
|
+
*/
|
|
1639
|
+
function mapListItemToUpcomingEvent(item) {
|
|
1640
|
+
const kind = resolveItemKind(item);
|
|
1641
|
+
const timezone = item?.timeZone ?? '';
|
|
1642
|
+
const dayIndicator = item?.dayIndicator ??
|
|
1643
|
+
(kind === UpcomingItemKind.EVENT
|
|
1644
|
+
? computeDayIndicator(item?.startDateTime, item?.endDateTime, timezone)
|
|
1645
|
+
: '');
|
|
1646
|
+
return {
|
|
1647
|
+
eventId: item?.id ?? item?.eventId ?? item?.meetingId ?? '',
|
|
1648
|
+
kind,
|
|
1649
|
+
// The list endpoint uses `name`; fall back to `meetingTitle` for meeting rows.
|
|
1650
|
+
title: item?.name ?? item?.meetingTitle ?? '',
|
|
1651
|
+
// The list screen copies status into contentUnderLink; accept either.
|
|
1652
|
+
status: item?.status ?? item?.contentUnderLink ?? '',
|
|
1653
|
+
dayIndicator,
|
|
1654
|
+
meetingCount: kind === UpcomingItemKind.STANDALONE_MEETING
|
|
1655
|
+
? 1
|
|
1656
|
+
: item?.meetingCount ?? 0,
|
|
1657
|
+
openForAttendanceCount: item?.openForAttendanceCount ?? 0,
|
|
1658
|
+
startDateTime: item?.startDateTime,
|
|
1659
|
+
endDateTime: item?.endDateTime,
|
|
1660
|
+
timezone,
|
|
1661
|
+
groupOrCommittee: item?.groupName ?? item?.groupAcronym ?? '',
|
|
1662
|
+
roomOrLocation: item?.meetingLocation ?? item?.room ?? '',
|
|
1663
|
+
isMemberOfGroup: item?.isMemberOfGroup ?? false,
|
|
1664
|
+
meetings: [],
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Maps a raw backend list of events & meetings into the dashboard view models,
|
|
1669
|
+
* enforcing that STANDALONE_MEETING rows always sort LAST while preserving the
|
|
1670
|
+
* backend's within-group ordering for each partition (stable sort).
|
|
1671
|
+
* @param {EventMeetingListItem[]} items - The raw list items.
|
|
1672
|
+
* @return {UpcomingEvent[]} The mapped, standalone-last ordered view models.
|
|
1673
|
+
*/
|
|
1674
|
+
function mapEventMeetingList(items) {
|
|
1675
|
+
const mapped = (items ?? []).map((item) => mapListItemToUpcomingEvent(item));
|
|
1676
|
+
const events = mapped.filter((entry) => entry.kind === UpcomingItemKind.EVENT);
|
|
1677
|
+
const standalone = mapped.filter((entry) => entry.kind === UpcomingItemKind.STANDALONE_MEETING);
|
|
1678
|
+
return [...events, ...standalone];
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Maps a raw backend child-meeting detail item to the {@link MeetingRow} view
|
|
1682
|
+
* model used by the event block's expanded meeting list.
|
|
1683
|
+
* @param {EventMeetingDetailItem} item - The raw child-meeting item.
|
|
1684
|
+
* @return {MeetingRow} The mapped meeting row.
|
|
1685
|
+
*/
|
|
1686
|
+
function mapDetailItemToMeetingRow(item) {
|
|
1687
|
+
const status = item?.status ?? '';
|
|
1688
|
+
// A meeting is "open for attendance" while it is In Progress. The
|
|
1689
|
+
// meetingsDetails endpoint has no dedicated flag, so derive it from status
|
|
1690
|
+
// (honouring an explicit backend flag when one is provided).
|
|
1691
|
+
const isOpenForAttendance = item?.isOpenForAttendance ?? status.trim().toLowerCase() === 'in progress';
|
|
1692
|
+
return {
|
|
1693
|
+
meetingId: item?.meetingId ?? '',
|
|
1694
|
+
meetingName: item?.meetingTitle ?? '',
|
|
1695
|
+
groupOrCommittee: item?.groupName ?? '',
|
|
1696
|
+
roomOrLocation: item?.meetingLocation ?? '',
|
|
1697
|
+
startDateTime: item?.meetingStDate,
|
|
1698
|
+
endDateTime: item?.meetingEdDate,
|
|
1699
|
+
timezone: item?.timeZone ?? '',
|
|
1700
|
+
status,
|
|
1701
|
+
isMemberOfGroup: item?.isMemberOfGroup ?? false,
|
|
1702
|
+
isOpenForAttendance,
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Maps a raw backend list of child-meeting detail items to {@link MeetingRow}
|
|
1707
|
+
* view models.
|
|
1708
|
+
* @param {EventMeetingDetailItem[]} items - The raw child-meeting items.
|
|
1709
|
+
* @return {MeetingRow[]} The mapped meeting rows.
|
|
1710
|
+
*/
|
|
1711
|
+
function mapEventMeetingDetails(items) {
|
|
1712
|
+
return (items ?? []).map((item) => mapDetailItemToMeetingRow(item));
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
/**
|
|
1716
|
+
* Pure reducers for the dashboard attendance state. These functions never
|
|
1717
|
+
* mutate their inputs; each returns a new object/set so they can be exercised
|
|
1718
|
+
* directly by property tests and composed by the DashboardService.
|
|
1719
|
+
*/
|
|
1720
|
+
/**
|
|
1721
|
+
* Produce a new attendance-state map with the target meeting set to
|
|
1722
|
+
* CURRENTLY_ATTENDING. Every other entry is copied unchanged (frame property).
|
|
1723
|
+
*
|
|
1724
|
+
* @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).
|
|
1725
|
+
* @param {string} meetingId The meeting whose state transitions to CURRENTLY_ATTENDING.
|
|
1726
|
+
* @return {Record<string, AttendanceState>} A new map reflecting the successful log-attendance action.
|
|
1727
|
+
*/
|
|
1728
|
+
const applyLogAttendanceSuccess = (map, meetingId) => ({
|
|
1729
|
+
...map,
|
|
1730
|
+
[meetingId]: AttendanceState.CURRENTLY_ATTENDING,
|
|
1731
|
+
});
|
|
1732
|
+
/**
|
|
1733
|
+
* Produce a new attendance-state map with the target meeting set to
|
|
1734
|
+
* NOT_ATTENDING. Every other entry is copied unchanged (frame property).
|
|
1735
|
+
*
|
|
1736
|
+
* @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).
|
|
1737
|
+
* @param {string} meetingId The meeting whose state transitions to NOT_ATTENDING.
|
|
1738
|
+
* @return {Record<string, AttendanceState>} A new map reflecting the successful leave-meeting action.
|
|
1739
|
+
*/
|
|
1740
|
+
const applyLeaveMeetingSuccess = (map, meetingId) => ({
|
|
1741
|
+
...map,
|
|
1742
|
+
[meetingId]: AttendanceState.NOT_ATTENDING,
|
|
1743
|
+
});
|
|
1744
|
+
/**
|
|
1745
|
+
* Add a meeting to the in-flight set, returning a new set. Prior membership is
|
|
1746
|
+
* retained so the displayed attendance state is preserved while the request
|
|
1747
|
+
* resolves.
|
|
1748
|
+
*
|
|
1749
|
+
* @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).
|
|
1750
|
+
* @param {string} meetingId The meeting whose attendance action has started.
|
|
1751
|
+
* @return {Set<string>} A new set that additionally contains the meeting id.
|
|
1752
|
+
*/
|
|
1753
|
+
const beginAttendanceAction = (set, meetingId) => new Set([...set, meetingId]);
|
|
1754
|
+
/**
|
|
1755
|
+
* Remove a meeting from the in-flight set, returning a new set. All other
|
|
1756
|
+
* in-flight ids are retained.
|
|
1757
|
+
*
|
|
1758
|
+
* @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).
|
|
1759
|
+
* @param {string} meetingId The meeting whose attendance action has resolved.
|
|
1760
|
+
* @return {Set<string>} A new set that no longer contains the meeting id.
|
|
1761
|
+
*/
|
|
1762
|
+
const endAttendanceAction = (set, meetingId) => {
|
|
1763
|
+
const next = new Set(set);
|
|
1764
|
+
next.delete(meetingId);
|
|
1765
|
+
return next;
|
|
1766
|
+
};
|
|
1767
|
+
|
|
1768
|
+
/** Fallback label for an empty group type / member level, matching the My Groups tab. */
|
|
1769
|
+
const UNASSIGNED_LABEL = 'Unassigned';
|
|
1770
|
+
/** Placeholder for an empty cell value. */
|
|
1771
|
+
const EMPTY_VALUE = '-';
|
|
1772
|
+
/** Statuses included in the upcoming section, matching the view-events-meetings-list screen. */
|
|
1773
|
+
const UPCOMING_STATUSES = ['In Progress', 'Upcoming'];
|
|
1774
|
+
/** Sort column used for the top-level events & meetings list. */
|
|
1775
|
+
const UPCOMING_SORT_COLUMN = 'startDateTime';
|
|
1776
|
+
/** Sort column used for an event's expanded child-meeting list (meetingsDetails). */
|
|
1777
|
+
const EVENT_MEETINGS_SORT_COLUMN = 'meetingStDate';
|
|
1778
|
+
/** Default page size for the top-level upcoming section list. */
|
|
1779
|
+
const UPCOMING_PAGE_SIZE = 10;
|
|
1780
|
+
/** Default page size for an event's expanded child-meeting list. */
|
|
1781
|
+
const EVENT_MEETINGS_PAGE_SIZE = 5;
|
|
1782
|
+
/** Large page size used by the eager count prefetch to capture the full set. */
|
|
1783
|
+
const EVENT_COUNT_PAGE_SIZE = 200;
|
|
1784
|
+
/**
|
|
1785
|
+
* DashboardService is the single source of truth for the dashboard landing
|
|
1786
|
+
* page's data and attendance state. It mirrors the `events-and-meetings`
|
|
1787
|
+
* service conventions: it is a `providedIn: 'root'` singleton, holds the host
|
|
1788
|
+
* `apiBaseUrl` / `userPermissions` set via {@link setAppConfig}, owns its state
|
|
1789
|
+
* via `BehaviorSubject`s exposed as observables, and reaches the backend only
|
|
1790
|
+
* through the shared `HttpService` from `@ieeesa-npm/utility` (never
|
|
1791
|
+
* `HttpClient` directly).
|
|
1792
|
+
*
|
|
1793
|
+
* The upcoming-events load calls the real `POST /meetings/eventsAndMeetings`
|
|
1794
|
+
* endpoint (child meetings are lazily loaded per-event via
|
|
1795
|
+
* `POST /meetings/meetingsDetails`); the groups load calls `GET
|
|
1796
|
+
* /groups/my-groups`. The attendance actions compose the pure reducers from
|
|
1797
|
+
* `attendance-reducers.ts` so the displayed `AttendanceState` only advances on a
|
|
1798
|
+
* successful resolution and the prior state is retained on failure.
|
|
1799
|
+
* @export
|
|
1800
|
+
* @class DashboardService
|
|
1801
|
+
*/
|
|
1802
|
+
class DashboardService {
|
|
1803
|
+
constructor(
|
|
1804
|
+
// eslint-disable-next-line no-unused-vars
|
|
1805
|
+
httpService // eslint-disable-next-line no-empty-function
|
|
1806
|
+
) {
|
|
1807
|
+
this.httpService = httpService;
|
|
1808
|
+
this.upcomingEvents = new BehaviorSubject([]);
|
|
1809
|
+
this.groups = new BehaviorSubject([]);
|
|
1810
|
+
this.upcomingState = new BehaviorSubject(DashboardSectionState.LOADING);
|
|
1811
|
+
this.groupsState = new BehaviorSubject(DashboardSectionState.LOADING);
|
|
1812
|
+
this.attendanceStates = new BehaviorSubject({});
|
|
1813
|
+
this.inFlightMeetingIds = new BehaviorSubject(new Set());
|
|
1814
|
+
/** Emits the list of the user's upcoming events. */
|
|
1815
|
+
this.upcomingEvents$ = this.upcomingEvents.asObservable();
|
|
1816
|
+
/** Emits the list of the user's groups. */
|
|
1817
|
+
this.groups$ = this.groups.asObservable();
|
|
1818
|
+
/** Emits the load/empty/error state of the upcoming-events section. */
|
|
1819
|
+
this.upcomingState$ = this.upcomingState.asObservable();
|
|
1820
|
+
/** Emits the load/empty/error state of the groups section. */
|
|
1821
|
+
this.groupsState$ = this.groupsState.asObservable();
|
|
1822
|
+
/** Emits the per-meeting attendance-state map. */
|
|
1823
|
+
this.attendanceStates$ = this.attendanceStates.asObservable();
|
|
1824
|
+
/** Emits the set of meeting ids with an attendance action in flight. */
|
|
1825
|
+
this.inFlightMeetingIds$ = this.inFlightMeetingIds.asObservable();
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Stores the host-supplied API base URL and user permissions used to build
|
|
1829
|
+
* request URLs and gate permission-controlled actions. Mirrors the
|
|
1830
|
+
* `events-and-meetings` service `setAppConfig`.
|
|
1831
|
+
* @param {string} apiBaseURL - The host application's API base URL.
|
|
1832
|
+
* @param {UserPermission[]} userPermissions - The signed-in user's permissions.
|
|
1833
|
+
* @return {void}
|
|
1834
|
+
* @memberof DashboardService
|
|
1835
|
+
*/
|
|
1836
|
+
setAppConfig(apiBaseURL, userPermissions) {
|
|
1837
|
+
this.apiBaseUrl = apiBaseURL;
|
|
1838
|
+
this.userPermissions = userPermissions;
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Loads the user's upcoming events & meetings from the real backend via
|
|
1842
|
+
* `POST {apiBaseUrl}/meetings/eventsAndMeetings`, the same endpoint the
|
|
1843
|
+
* `view-events-meetings-list` screen uses. The response is mapped into the
|
|
1844
|
+
* dashboard view models (with STANDALONE_MEETING rows ordered last), the
|
|
1845
|
+
* per-meeting attendance-state map is seeded, and the section advances through
|
|
1846
|
+
* LOADING → LOADED/EMPTY on success, leaving the caller to set ERROR on
|
|
1847
|
+
* failure. Follows the shared `pipe(map, catchError(throw))` pattern.
|
|
1848
|
+
* @return {Observable<EventMeetingListResponse>} The upcoming events & meetings response envelope.
|
|
1849
|
+
* @memberof DashboardService
|
|
1850
|
+
*/
|
|
1851
|
+
loadUpcomingEvents() {
|
|
1852
|
+
this.upcomingState.next(DashboardSectionState.LOADING);
|
|
1853
|
+
const payload = {
|
|
1854
|
+
payload: {
|
|
1855
|
+
eventId: null,
|
|
1856
|
+
sortColumn: UPCOMING_SORT_COLUMN,
|
|
1857
|
+
ascendingOrder: true,
|
|
1858
|
+
page: 1,
|
|
1859
|
+
size: UPCOMING_PAGE_SIZE,
|
|
1860
|
+
filter: {
|
|
1861
|
+
status: UPCOMING_STATUSES,
|
|
1862
|
+
isAllMeetingSelected: false,
|
|
1863
|
+
},
|
|
1864
|
+
},
|
|
1865
|
+
};
|
|
1866
|
+
return this.httpService
|
|
1867
|
+
.postData(`${this.apiBaseUrl}/meetings/eventsAndMeetings`, payload)
|
|
1868
|
+
.pipe(map((response) => {
|
|
1869
|
+
const events = mapEventMeetingList(response?.body?.eventMeetingList ?? []);
|
|
1870
|
+
this.upcomingEvents.next(events);
|
|
1871
|
+
this.seedAttendanceStates(events);
|
|
1872
|
+
this.upcomingState.next(events.length > 0
|
|
1873
|
+
? DashboardSectionState.LOADED
|
|
1874
|
+
: DashboardSectionState.EMPTY);
|
|
1875
|
+
// Eagerly fetch each EVENT's meeting count so the "{n} meetings" and
|
|
1876
|
+
// "{n} open for attendance" summaries are correct before expanding.
|
|
1877
|
+
this.loadEventCounts(events);
|
|
1878
|
+
return response;
|
|
1879
|
+
}), catchError((error) => {
|
|
1880
|
+
this.upcomingState.next(DashboardSectionState.ERROR);
|
|
1881
|
+
throw error;
|
|
1882
|
+
}));
|
|
1883
|
+
}
|
|
1884
|
+
/**
|
|
1885
|
+
* Lazily loads (and paginates) the child meetings of an EVENT row via
|
|
1886
|
+
* `POST {apiBaseUrl}/meetings/meetingsDetails` — the per-event expand endpoint
|
|
1887
|
+
* used by the reference screen. On success the loaded meetings are mapped and
|
|
1888
|
+
* merged onto the matching event in the `upcomingEvents` list (with its
|
|
1889
|
+
* `meetingCount` / `openForAttendanceCount` refreshed), and the per-meeting
|
|
1890
|
+
* attendance-state map is extended. Each event paginates independently.
|
|
1891
|
+
* @param {string} eventId - The event whose meetings to load.
|
|
1892
|
+
* @param {number} [page=1] - The one-based page to request.
|
|
1893
|
+
* @param {number} [size=EVENT_MEETINGS_PAGE_SIZE] - The page size.
|
|
1894
|
+
* @return {Observable<EventMeetingDetailResponse>} The child-meetings response envelope.
|
|
1895
|
+
* @memberof DashboardService
|
|
1896
|
+
*/
|
|
1897
|
+
loadEventMeetings(eventId, page = 1, size = EVENT_MEETINGS_PAGE_SIZE) {
|
|
1898
|
+
return this.fetchEventMeetingsPage(eventId, page, size).pipe(map((response) => {
|
|
1899
|
+
const meetings = mapEventMeetingDetails(response?.body?.meetings ?? []);
|
|
1900
|
+
const total = response?.body?.totalRecords ?? meetings.length;
|
|
1901
|
+
// Prefer the already-known full open count on the event; fall back to
|
|
1902
|
+
// the current page's open count when it hasn't been prefetched.
|
|
1903
|
+
const existing = this.upcomingEvents.value.find((event) => event.eventId === eventId);
|
|
1904
|
+
const pageOpenCount = meetings.filter((meeting) => meeting.isOpenForAttendance).length;
|
|
1905
|
+
const openForAttendanceCount = existing?.openForAttendanceCount || pageOpenCount;
|
|
1906
|
+
this.mergeEventMeetings(eventId, meetings, total, openForAttendanceCount);
|
|
1907
|
+
this.seedAttendanceStatesFromMeetings(meetings);
|
|
1908
|
+
return response;
|
|
1909
|
+
}), catchError((error) => {
|
|
1910
|
+
throw error;
|
|
1911
|
+
}));
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Merges a freshly loaded page of child meetings onto the matching event in
|
|
1915
|
+
* the `upcomingEvents` list, refreshing the event's `meetings`,
|
|
1916
|
+
* `meetingCount` (from the backend `totalRecords`), and
|
|
1917
|
+
* `openForAttendanceCount`. Leaves all other events untouched.
|
|
1918
|
+
* @param {string} eventId - The event to merge meetings onto.
|
|
1919
|
+
* @param {MeetingRow[]} meetings - The mapped child meetings for the page.
|
|
1920
|
+
* @param {number} totalRecords - The event's total meeting count from the backend.
|
|
1921
|
+
* @return {void}
|
|
1922
|
+
* @memberof DashboardService
|
|
1923
|
+
*/
|
|
1924
|
+
mergeEventMeetings(eventId, meetings, totalRecords, openForAttendanceCount) {
|
|
1925
|
+
const next = this.upcomingEvents.value.map((event) => {
|
|
1926
|
+
if (event.eventId !== eventId) {
|
|
1927
|
+
return event;
|
|
1928
|
+
}
|
|
1929
|
+
return {
|
|
1930
|
+
...event,
|
|
1931
|
+
meetings,
|
|
1932
|
+
meetingCount: totalRecords,
|
|
1933
|
+
openForAttendanceCount,
|
|
1934
|
+
};
|
|
1935
|
+
});
|
|
1936
|
+
this.upcomingEvents.next(next);
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Eagerly fetches each EVENT's total meeting count and open-for-attendance
|
|
1940
|
+
* count by requesting a large first page of its child meetings, then merging
|
|
1941
|
+
* only the counts (not the rows) so the collapsed card summaries are accurate
|
|
1942
|
+
* before the user expands. Standalone meetings are skipped. Failures per event
|
|
1943
|
+
* are swallowed so one failing count never breaks the list.
|
|
1944
|
+
* @param {UpcomingEvent[]} events - The loaded events to fetch counts for.
|
|
1945
|
+
* @return {void}
|
|
1946
|
+
* @memberof DashboardService
|
|
1947
|
+
*/
|
|
1948
|
+
loadEventCounts(events) {
|
|
1949
|
+
events
|
|
1950
|
+
.filter((event) => event.kind === UpcomingItemKind.EVENT && event.eventId)
|
|
1951
|
+
.forEach((event) => {
|
|
1952
|
+
this.fetchEventMeetingsPage(event.eventId, 1, EVENT_COUNT_PAGE_SIZE)
|
|
1953
|
+
.pipe(catchError(() => of(null)))
|
|
1954
|
+
.subscribe((response) => {
|
|
1955
|
+
if (!response) {
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
const meetings = mapEventMeetingDetails(response?.body?.meetings ?? []);
|
|
1959
|
+
const total = response?.body?.totalRecords ?? meetings.length;
|
|
1960
|
+
const openCount = meetings.filter((meeting) => meeting.isOpenForAttendance).length;
|
|
1961
|
+
this.mergeEventCounts(event.eventId, total, openCount);
|
|
1962
|
+
this.seedAttendanceStatesFromMeetings(meetings);
|
|
1963
|
+
});
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
/**
|
|
1967
|
+
* Merges only the meeting counts onto the matching event, leaving its
|
|
1968
|
+
* `meetings` rows untouched (used by the eager count prefetch).
|
|
1969
|
+
* @param {string} eventId - The event to update.
|
|
1970
|
+
* @param {number} totalRecords - The event's total meeting count.
|
|
1971
|
+
* @param {number} openForAttendanceCount - The open-for-attendance count.
|
|
1972
|
+
* @return {void}
|
|
1973
|
+
* @memberof DashboardService
|
|
1974
|
+
*/
|
|
1975
|
+
mergeEventCounts(eventId, totalRecords, openForAttendanceCount) {
|
|
1976
|
+
const next = this.upcomingEvents.value.map((event) => event.eventId === eventId
|
|
1977
|
+
? { ...event, meetingCount: totalRecords, openForAttendanceCount }
|
|
1978
|
+
: event);
|
|
1979
|
+
this.upcomingEvents.next(next);
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Builds and posts the `meetingsDetails` request for a single event page,
|
|
1983
|
+
* returning the raw response envelope. Shared by {@link loadEventMeetings} and
|
|
1984
|
+
* the eager count prefetch.
|
|
1985
|
+
* @param {string} eventId - The event whose meetings to fetch.
|
|
1986
|
+
* @param {number} page - The one-based page to request.
|
|
1987
|
+
* @param {number} size - The page size.
|
|
1988
|
+
* @return {Observable<EventMeetingDetailResponse>} The child-meetings response.
|
|
1989
|
+
* @memberof DashboardService
|
|
1990
|
+
*/
|
|
1991
|
+
fetchEventMeetingsPage(eventId, page, size) {
|
|
1992
|
+
const payload = {
|
|
1993
|
+
payload: {
|
|
1994
|
+
eventId,
|
|
1995
|
+
sortColumn: EVENT_MEETINGS_SORT_COLUMN,
|
|
1996
|
+
ascendingOrder: true,
|
|
1997
|
+
page,
|
|
1998
|
+
size,
|
|
1999
|
+
filter: {
|
|
2000
|
+
status: UPCOMING_STATUSES,
|
|
2001
|
+
isAllMeetingSelected: false,
|
|
2002
|
+
},
|
|
2003
|
+
},
|
|
2004
|
+
};
|
|
2005
|
+
return this.httpService.postData(`${this.apiBaseUrl}/meetings/meetingsDetails`, payload);
|
|
2006
|
+
}
|
|
2007
|
+
/**
|
|
2008
|
+
* Loads the user's groups, driving the groups section through
|
|
2009
|
+
* LOADING → LOADED/EMPTY on success and leaving the caller to set ERROR on
|
|
2010
|
+
* failure. Follows the `pipe(map, catchError(throw))` pattern.
|
|
2011
|
+
*
|
|
2012
|
+
* TODO: Replace mock with real API call when BE is ready
|
|
2013
|
+
* @return {Observable<DashboardListResponse<GroupRow[]>>} The groups response envelope.
|
|
2014
|
+
* @memberof DashboardService
|
|
2015
|
+
*/
|
|
2016
|
+
loadGroups() {
|
|
2017
|
+
this.groupsState.next(DashboardSectionState.LOADING);
|
|
2018
|
+
return this.httpService
|
|
2019
|
+
.getData(`${this.apiBaseUrl}/groups/my-groups`)
|
|
2020
|
+
.pipe(map((response) => {
|
|
2021
|
+
const groups = (response?.body?.groups ?? []).map((group) => this.mapGroup(group));
|
|
2022
|
+
this.groups.next(groups);
|
|
2023
|
+
this.groupsState.next(groups.length > 0
|
|
2024
|
+
? DashboardSectionState.LOADED
|
|
2025
|
+
: DashboardSectionState.EMPTY);
|
|
2026
|
+
return response;
|
|
2027
|
+
}), catchError((error) => {
|
|
2028
|
+
this.groupsState.next(DashboardSectionState.ERROR);
|
|
2029
|
+
throw error;
|
|
2030
|
+
}));
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Maps a backend {@link MyGroupView} to the table-facing {@link GroupRow}.
|
|
2034
|
+
* Mirrors the My Groups profile tab: the type falls back to "Unassigned" when
|
|
2035
|
+
* `groupTypeName` is null, affiliations are comma-joined, empty officer role /
|
|
2036
|
+
* affiliation render as a placeholder, and a blank member level becomes
|
|
2037
|
+
* "Unassigned" (rendered as the warning pill by the Your Groups component).
|
|
2038
|
+
* @param {MyGroupView} group - The backend group view.
|
|
2039
|
+
* @return {GroupRow}
|
|
2040
|
+
* @memberof DashboardService
|
|
2041
|
+
*/
|
|
2042
|
+
mapGroup(group) {
|
|
2043
|
+
// The backend returns officer roles as an `officer` array of
|
|
2044
|
+
// { officerId, officerName }. Join the names for the Officer Role column
|
|
2045
|
+
// (e.g. "Chair" or "Chair, Vice Chair"); show the placeholder when empty.
|
|
2046
|
+
const officerRole = (group.officer ?? [])
|
|
2047
|
+
.map((officer) => officer?.officerName?.trim())
|
|
2048
|
+
.filter((name) => !!name)
|
|
2049
|
+
.join(', ') || EMPTY_VALUE;
|
|
2050
|
+
return {
|
|
2051
|
+
groupId: group.groupId,
|
|
2052
|
+
group: group.groupName,
|
|
2053
|
+
type: group.groupTypeName || group.groupType || UNASSIGNED_LABEL,
|
|
2054
|
+
officerRole,
|
|
2055
|
+
affiliation: group.affiliations?.join(', ') || EMPTY_VALUE,
|
|
2056
|
+
memberLevel: group.memberLevel?.trim() || UNASSIGNED_LABEL,
|
|
2057
|
+
// Carry the ancestor hierarchy through for the expandable hierarchy rows.
|
|
2058
|
+
hierarchy: group.hierarchy ?? [],
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Logs attendance for a meeting. Marks the meeting in-flight (retaining the
|
|
2063
|
+
* prior displayed state), posts through `HttpService`, applies the
|
|
2064
|
+
* log-attendance-success reducer on success, clears the in-flight flag on
|
|
2065
|
+
* completion, and rethrows while retaining prior state on failure.
|
|
2066
|
+
* @param {string} meetingId - The meeting to log attendance for.
|
|
2067
|
+
* @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.
|
|
2068
|
+
* @memberof DashboardService
|
|
2069
|
+
*/
|
|
2070
|
+
logAttendance(meetingId) {
|
|
2071
|
+
this.inFlightMeetingIds.next(beginAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2072
|
+
return this.httpService
|
|
2073
|
+
.postData(`${this.apiBaseUrl}/meetings/attendance/log`, { meetingId })
|
|
2074
|
+
.pipe(map((response) => {
|
|
2075
|
+
this.attendanceStates.next(applyLogAttendanceSuccess(this.attendanceStates.value, meetingId));
|
|
2076
|
+
this.inFlightMeetingIds.next(endAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2077
|
+
return response;
|
|
2078
|
+
}), catchError((error) => {
|
|
2079
|
+
// Retain prior attendance state; only clear the in-flight flag.
|
|
2080
|
+
this.inFlightMeetingIds.next(endAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2081
|
+
throw error;
|
|
2082
|
+
}));
|
|
2083
|
+
}
|
|
2084
|
+
/**
|
|
2085
|
+
* Leaves a meeting. Marks the meeting in-flight (retaining the prior
|
|
2086
|
+
* displayed state), posts through `HttpService`, applies the
|
|
2087
|
+
* leave-meeting-success reducer on success, clears the in-flight flag on
|
|
2088
|
+
* completion, and rethrows while retaining prior state on failure.
|
|
2089
|
+
* @param {string} meetingId - The meeting to leave.
|
|
2090
|
+
* @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.
|
|
2091
|
+
* @memberof DashboardService
|
|
2092
|
+
*/
|
|
2093
|
+
leaveMeeting(meetingId) {
|
|
2094
|
+
this.inFlightMeetingIds.next(beginAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2095
|
+
return this.httpService
|
|
2096
|
+
.postData(`${this.apiBaseUrl}/meetings/attendance/leave`, { meetingId })
|
|
2097
|
+
.pipe(map((response) => {
|
|
2098
|
+
this.attendanceStates.next(applyLeaveMeetingSuccess(this.attendanceStates.value, meetingId));
|
|
2099
|
+
this.inFlightMeetingIds.next(endAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2100
|
+
return response;
|
|
2101
|
+
}), catchError((error) => {
|
|
2102
|
+
// Retain prior attendance state; only clear the in-flight flag.
|
|
2103
|
+
this.inFlightMeetingIds.next(endAttendanceAction(this.inFlightMeetingIds.value, meetingId));
|
|
2104
|
+
throw error;
|
|
2105
|
+
}));
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Returns a synchronous snapshot of the per-meeting attendance-state map.
|
|
2109
|
+
* @return {Record<string, AttendanceState>} The current attendance-state map.
|
|
2110
|
+
* @memberof DashboardService
|
|
2111
|
+
*/
|
|
2112
|
+
getAttendanceStatesSnapshot() {
|
|
2113
|
+
return this.attendanceStates.value;
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Seeds the attendance-state map from a freshly loaded list of events, using
|
|
2117
|
+
* each meeting's `attendanceState` (defaulting to `NOT_ATTENDING`). Keeps the
|
|
2118
|
+
* displayed state in sync with the data load without overwriting ids that are
|
|
2119
|
+
* not present in the new list.
|
|
2120
|
+
* @param {UpcomingEvent[]} events - The loaded upcoming events.
|
|
2121
|
+
* @return {void}
|
|
2122
|
+
* @memberof DashboardService
|
|
2123
|
+
*/
|
|
2124
|
+
seedAttendanceStates(events) {
|
|
2125
|
+
const meetings = events.flatMap((event) => event.meetings ?? []);
|
|
2126
|
+
this.seedAttendanceStatesFromMeetings(meetings);
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Seeds the attendance-state map from a list of meeting rows, using each
|
|
2130
|
+
* meeting's `attendanceState` (defaulting to `NOT_ATTENDING`) without
|
|
2131
|
+
* overwriting ids absent from the new list. Shared by the list load and the
|
|
2132
|
+
* per-event expand so freshly loaded child meetings pick up their state.
|
|
2133
|
+
* @param {MeetingRow[]} meetings - The meeting rows to seed from.
|
|
2134
|
+
* @return {void}
|
|
2135
|
+
* @memberof DashboardService
|
|
2136
|
+
*/
|
|
2137
|
+
seedAttendanceStatesFromMeetings(meetings) {
|
|
2138
|
+
const next = {
|
|
2139
|
+
...this.attendanceStates.value,
|
|
2140
|
+
};
|
|
2141
|
+
meetings.forEach((meeting) => {
|
|
2142
|
+
if (meeting.meetingId) {
|
|
2143
|
+
next[meeting.meetingId] =
|
|
2144
|
+
meeting.attendanceState ??
|
|
2145
|
+
next[meeting.meetingId] ??
|
|
2146
|
+
AttendanceState.NOT_ATTENDING;
|
|
2147
|
+
}
|
|
2148
|
+
});
|
|
2149
|
+
this.attendanceStates.next(next);
|
|
2150
|
+
}
|
|
2151
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardService, deps: [{ token: i1$1.HttpService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2152
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardService, providedIn: 'root' }); }
|
|
2153
|
+
}
|
|
2154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardService, decorators: [{
|
|
2155
|
+
type: Injectable,
|
|
2156
|
+
args: [{
|
|
2157
|
+
providedIn: 'root',
|
|
2158
|
+
}]
|
|
2159
|
+
}], ctorParameters: function () { return [{ type: i1$1.HttpService }]; } });
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* Permission identifiers (by name) that gate the dashboard attendance actions.
|
|
2163
|
+
* Mirrors the permission-type pattern used by the `events-and-meetings` and
|
|
2164
|
+
* `groups` user-permissions services.
|
|
2165
|
+
*/
|
|
2166
|
+
/* eslint-disable no-unused-vars */
|
|
2167
|
+
var DashboardPermissionType;
|
|
2168
|
+
(function (DashboardPermissionType) {
|
|
2169
|
+
DashboardPermissionType["LOG_ATTENDANCE"] = "Log Attendance";
|
|
2170
|
+
DashboardPermissionType["LEAVE_MEETING"] = "Leave Meeting";
|
|
2171
|
+
})(DashboardPermissionType || (DashboardPermissionType = {}));
|
|
2172
|
+
/* eslint-enable no-unused-vars */
|
|
2173
|
+
class UserPermissionsService {
|
|
2174
|
+
/**
|
|
2175
|
+
* Returns access provision for the passed action/feature based on whether the signed in user has appropriate permission.
|
|
2176
|
+
* @param {DashboardPermissionType} permission
|
|
2177
|
+
* @param {UserPermission[]} userPermissions
|
|
2178
|
+
* @return {boolean}
|
|
2179
|
+
* @memberof UserPermissionsService
|
|
2180
|
+
*/
|
|
2181
|
+
validateAccessPermission(permission, userPermissions) {
|
|
2182
|
+
const isPermitted = userPermissions?.length > 0
|
|
2183
|
+
? userPermissions?.some(({ permissionName }) => permissionName === permission)
|
|
2184
|
+
: false;
|
|
2185
|
+
return isPermitted;
|
|
2186
|
+
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Maps the host-supplied user permissions to the attendance-action permissions consumed by the dashboard rows.
|
|
2189
|
+
* @param {UserPermission[]} userPermissions
|
|
2190
|
+
* @return {AttendanceActionPermissions}
|
|
2191
|
+
* @memberof UserPermissionsService
|
|
2192
|
+
*/
|
|
2193
|
+
mapToAttendanceActionPermissions(userPermissions) {
|
|
2194
|
+
return {
|
|
2195
|
+
canLogAttendance: this.validateAccessPermission(DashboardPermissionType.LOG_ATTENDANCE, userPermissions),
|
|
2196
|
+
canLeaveMeeting: this.validateAccessPermission(DashboardPermissionType.LEAVE_MEETING, userPermissions),
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UserPermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2200
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UserPermissionsService, providedIn: 'root' }); }
|
|
2201
|
+
}
|
|
2202
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UserPermissionsService, decorators: [{
|
|
2203
|
+
type: Injectable,
|
|
2204
|
+
args: [{
|
|
2205
|
+
providedIn: 'root',
|
|
2206
|
+
}]
|
|
2207
|
+
}] });
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* Dashboard (`ieeesa-dashboard`) is the root container and single host entry
|
|
2211
|
+
* point for the "NESC Revision Cycle" dashboard landing page. It owns the
|
|
2212
|
+
* host-supplied configuration (`routePaths`, `apiBaseURL`, `userInfo`,
|
|
2213
|
+
* `userPermissions`), composes the four regions — welcome header, upcoming
|
|
2214
|
+
* meetings & events, your groups, and footer — and orchestrates data loading
|
|
2215
|
+
* and attendance actions through the {@link DashboardService}.
|
|
2216
|
+
*
|
|
2217
|
+
* The component is composition-first and host-agnostic: it subscribes to the
|
|
2218
|
+
* service observables (`upcomingEvents$`, `groups$`, the per-section states, the
|
|
2219
|
+
* attendance-state map, and the in-flight set) with `takeUntil(destroy$)` and
|
|
2220
|
+
* tracks `isMobileView` from the Presentation_Library
|
|
2221
|
+
* {@link BreakpointObserverService} (Req 13.1, 13.2, 13.5, 15.1, 15.2). Child
|
|
2222
|
+
* navigation `@Output()`s are composed into a single {@link dashboardNavigate}
|
|
2223
|
+
* stream of `{ path, id }` intents resolved from `routePaths` (falling back to
|
|
2224
|
+
* the default route configuration in `constants.json` when `routePaths` is
|
|
2225
|
+
* omitted) (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1, 11.5). Attendance `@Output()`s
|
|
2226
|
+
* are delegated to the service, and on failure the attendance-action error
|
|
2227
|
+
* message from `constants.json` is surfaced via the shared {@link AlertsService}
|
|
2228
|
+
* (Req 7.7, 7.8, 13.7). Per-row {@link AttendanceActionPermissions} are computed
|
|
2229
|
+
* from `userPermissions` and passed down to the rows (Req 12.3).
|
|
2230
|
+
* @export
|
|
2231
|
+
* @class DashboardComponent
|
|
2232
|
+
*/
|
|
2233
|
+
class DashboardComponent {
|
|
2234
|
+
/**
|
|
2235
|
+
* Total number of meetings across the loaded upcoming events, shown in the
|
|
2236
|
+
* welcome header's "Upcoming Meetings & Events" shortcut badge.
|
|
2237
|
+
* @readonly
|
|
2238
|
+
* @memberof DashboardComponent
|
|
2239
|
+
*/
|
|
2240
|
+
get meetingsCount() {
|
|
2241
|
+
return this.upcomingEvents.reduce((total, event) => total + (event?.meetingCount ?? 0), 0);
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* Number of loaded groups, shown in the welcome header's "Your Groups"
|
|
2245
|
+
* shortcut badge.
|
|
2246
|
+
* @readonly
|
|
2247
|
+
* @memberof DashboardComponent
|
|
2248
|
+
*/
|
|
2249
|
+
get groupsCount() {
|
|
2250
|
+
return this.groups.length;
|
|
2251
|
+
}
|
|
2252
|
+
constructor(
|
|
2253
|
+
// eslint-disable-next-line no-unused-vars
|
|
2254
|
+
dashboardService,
|
|
2255
|
+
// eslint-disable-next-line no-unused-vars
|
|
2256
|
+
userPermissionsService,
|
|
2257
|
+
// eslint-disable-next-line no-unused-vars
|
|
2258
|
+
breakpointObserverService,
|
|
2259
|
+
// eslint-disable-next-line no-unused-vars
|
|
2260
|
+
alertService // eslint-disable-next-line no-empty-function
|
|
2261
|
+
) {
|
|
2262
|
+
this.dashboardService = dashboardService;
|
|
2263
|
+
this.userPermissionsService = userPermissionsService;
|
|
2264
|
+
this.breakpointObserverService = breakpointObserverService;
|
|
2265
|
+
this.alertService = alertService;
|
|
2266
|
+
/** User-facing strings and the default route config sourced from `constants.json`. */
|
|
2267
|
+
this.constants = constants$1;
|
|
2268
|
+
/** Emits a resolved navigation intent for the host to act on (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1). */
|
|
2269
|
+
this.dashboardNavigate = new EventEmitter();
|
|
2270
|
+
/** The user's upcoming events, bound to the upcoming section (Req 13.1, 13.2). */
|
|
2271
|
+
this.upcomingEvents = [];
|
|
2272
|
+
/** The user's groups, bound to the groups section (Req 13.1, 13.2). */
|
|
2273
|
+
this.groups = [];
|
|
2274
|
+
/** The upcoming-events section's load/empty/error state (Req 13.1, 13.2, 13.5). */
|
|
2275
|
+
this.upcomingState = DashboardSectionState.LOADING;
|
|
2276
|
+
/** The groups section's load/empty/error state (Req 13.1, 13.2, 13.5). */
|
|
2277
|
+
this.groupsState = DashboardSectionState.LOADING;
|
|
2278
|
+
/** The per-meeting attendance-state map passed down to the rows. */
|
|
2279
|
+
this.attendanceStates = {};
|
|
2280
|
+
/** The set of meeting ids with an attendance action awaiting resolution. */
|
|
2281
|
+
this.inFlightMeetingIds = new Set();
|
|
2282
|
+
/** The per-row attendance-action permissions derived from `userPermissions` (Req 12.3). */
|
|
2283
|
+
this.attendancePermissions = {
|
|
2284
|
+
canLogAttendance: false,
|
|
2285
|
+
canLeaveMeeting: false,
|
|
2286
|
+
};
|
|
2287
|
+
/** Whether the viewport is at/below the mobile breakpoint (Req 15.1, 15.2). */
|
|
2288
|
+
this.isMobileView = false;
|
|
2289
|
+
/** Whether the Upcoming Meetings & Events card is expanded. Starts collapsed. */
|
|
2290
|
+
this.meetingsExpanded = false;
|
|
2291
|
+
/** Whether the Your Groups card is expanded. Starts collapsed. */
|
|
2292
|
+
this.groupsExpanded = false;
|
|
2293
|
+
/** The current zero-based page index of the groups table. */
|
|
2294
|
+
this.groupsPageIndex = 0;
|
|
2295
|
+
/** The current page size of the groups table (5 rows per page per the design). */
|
|
2296
|
+
this.groupsPageSize = 5;
|
|
2297
|
+
/** Completes on destroy to tear down all subscriptions (Req 2.4, 2.5). */
|
|
2298
|
+
this.destroy$ = new Subject();
|
|
2299
|
+
}
|
|
2300
|
+
/**
|
|
2301
|
+
* Initializes the dashboard: forwards the host config to the service, derives
|
|
2302
|
+
* the per-row attendance permissions, kicks off the upcoming-events and groups
|
|
2303
|
+
* loads, and wires up subscriptions to the service state observables and the
|
|
2304
|
+
* breakpoint observer — all cleaned up via `takeUntil(destroy$)` (Req 11.2,
|
|
2305
|
+
* 11.4, 12.3, 13.1, 13.2, 13.5, 15.1, 15.2).
|
|
2306
|
+
* @return {void}
|
|
2307
|
+
* @memberof DashboardComponent
|
|
2308
|
+
*/
|
|
2309
|
+
ngOnInit() {
|
|
2310
|
+
this.dashboardService.setAppConfig(this.apiBaseURL, this.userPermissions);
|
|
2311
|
+
this.attendancePermissions =
|
|
2312
|
+
this.userPermissionsService.mapToAttendanceActionPermissions(this.userPermissions);
|
|
2313
|
+
this.subscribeToServiceState();
|
|
2314
|
+
this.subscribeToBreakpoint();
|
|
2315
|
+
this.loadUpcomingEvents();
|
|
2316
|
+
this.loadGroups();
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Tears down all subscriptions on destroy (Req 2.4, 2.5).
|
|
2320
|
+
* @return {void}
|
|
2321
|
+
* @memberof DashboardComponent
|
|
2322
|
+
*/
|
|
2323
|
+
ngOnDestroy() {
|
|
2324
|
+
this.destroy$.next(true);
|
|
2325
|
+
this.destroy$.complete();
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Handles the welcome-header "Jump to" date selection. The dashboard currently
|
|
2329
|
+
* has no date-scoped data load, so the selection is accepted without side
|
|
2330
|
+
* effects; the hook keeps the header's contract satisfied for future filtering.
|
|
2331
|
+
* @return {void}
|
|
2332
|
+
* @memberof DashboardComponent
|
|
2333
|
+
*/
|
|
2334
|
+
onJumpToDateSelected() {
|
|
2335
|
+
// No date-scoped reload yet; retained for future date filtering (Req 4.4).
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* Handles a welcome-header "Jump to" shortcut: opens the matching section's
|
|
2339
|
+
* card (so its content is visible) and smoothly scrolls it into view. It does
|
|
2340
|
+
* NOT navigate away — the shortcut is an in-page jump to the section.
|
|
2341
|
+
* @param {DashboardJumpTarget} target - The selected shortcut target.
|
|
2342
|
+
* @return {void}
|
|
2343
|
+
* @memberof DashboardComponent
|
|
2344
|
+
*/
|
|
2345
|
+
onJumpToShortcut(target) {
|
|
2346
|
+
const section = target === DashboardJumpTarget.MEETINGS
|
|
2347
|
+
? this.upcomingSection
|
|
2348
|
+
: this.groupsSection;
|
|
2349
|
+
if (target === DashboardJumpTarget.MEETINGS) {
|
|
2350
|
+
this.meetingsExpanded = true;
|
|
2351
|
+
}
|
|
2352
|
+
else {
|
|
2353
|
+
this.groupsExpanded = true;
|
|
2354
|
+
}
|
|
2355
|
+
// Scroll after the expand has rendered so the target's final position is used.
|
|
2356
|
+
setTimeout(() => {
|
|
2357
|
+
section?.nativeElement?.scrollIntoView({
|
|
2358
|
+
behavior: 'smooth',
|
|
2359
|
+
block: 'start',
|
|
2360
|
+
});
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Emits the "View All" upcoming-events navigation intent, targeting the
|
|
2365
|
+
* `viewAllEvents` route with no id (Req 5.2, 11.1).
|
|
2366
|
+
* @return {void}
|
|
2367
|
+
* @memberof DashboardComponent
|
|
2368
|
+
*/
|
|
2369
|
+
onViewAllEvents() {
|
|
2370
|
+
this.emitNavigation(this.activeRouteConfig.viewAllEvents);
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* Emits the "View Event" navigation intent, targeting the `eventDetail` route
|
|
2374
|
+
* with the event id (Req 6.4, 11.1).
|
|
2375
|
+
* @param {string} eventId - The id of the event to view.
|
|
2376
|
+
* @return {void}
|
|
2377
|
+
* @memberof DashboardComponent
|
|
2378
|
+
*/
|
|
2379
|
+
onViewEvent(eventId) {
|
|
2380
|
+
this.emitNavigation(this.activeRouteConfig.eventDetail, eventId);
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* Emits the open-meeting navigation intent, targeting the `meetingDetail`
|
|
2384
|
+
* route with the meeting id (Req 7.4, 11.1).
|
|
2385
|
+
* @param {string} meetingId - The id of the meeting to open.
|
|
2386
|
+
* @return {void}
|
|
2387
|
+
* @memberof DashboardComponent
|
|
2388
|
+
*/
|
|
2389
|
+
onOpenMeeting(meetingId) {
|
|
2390
|
+
this.emitNavigation(this.activeRouteConfig.meetingDetail, meetingId);
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Emits the "View All" groups navigation intent, targeting the
|
|
2394
|
+
* `viewAllGroups` route with no id (Req 8.2, 11.1).
|
|
2395
|
+
* @return {void}
|
|
2396
|
+
* @memberof DashboardComponent
|
|
2397
|
+
*/
|
|
2398
|
+
onViewAllGroups() {
|
|
2399
|
+
this.emitNavigation(this.activeRouteConfig.viewAllGroups);
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* Emits the group-detail navigation intent, targeting the `groupDetail` route
|
|
2403
|
+
* with the group id (Req 8.7, 11.1).
|
|
2404
|
+
* @param {string} groupId - The id of the selected group.
|
|
2405
|
+
* @return {void}
|
|
2406
|
+
* @memberof DashboardComponent
|
|
2407
|
+
*/
|
|
2408
|
+
onGroupSelected(groupId) {
|
|
2409
|
+
this.emitNavigation(this.activeRouteConfig.groupDetail, groupId);
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2412
|
+
* Updates the groups table paging state in response to a paginator change so
|
|
2413
|
+
* the groups section reflects the requested page (Req 8.10).
|
|
2414
|
+
* @param {PageChange} page - The requested page index and size.
|
|
2415
|
+
* @return {void}
|
|
2416
|
+
* @memberof DashboardComponent
|
|
2417
|
+
*/
|
|
2418
|
+
onGroupsPageChange(page) {
|
|
2419
|
+
this.groupsPageIndex = page.pageIndex;
|
|
2420
|
+
this.groupsPageSize = page.pageSize;
|
|
2421
|
+
}
|
|
2422
|
+
/**
|
|
2423
|
+
* Lazily loads (or paginates) the child meetings of an expanded EVENT card via
|
|
2424
|
+
* the service, surfacing the attendance error message on failure. Each event
|
|
2425
|
+
* paginates independently.
|
|
2426
|
+
* @param {{ eventId: string; page: number }} request - The event id and one-based page to load.
|
|
2427
|
+
* @return {void}
|
|
2428
|
+
* @memberof DashboardComponent
|
|
2429
|
+
*/
|
|
2430
|
+
onLoadEventMeetings(request) {
|
|
2431
|
+
if (!request?.eventId) {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
this.dashboardService
|
|
2435
|
+
.loadEventMeetings(request.eventId, request.page)
|
|
2436
|
+
.pipe(takeUntil(this.destroy$))
|
|
2437
|
+
.subscribe({
|
|
2438
|
+
error: () => this.showAttendanceError(),
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Delegates a log-attendance request to the service, surfacing the
|
|
2443
|
+
* attendance-action error message via the shared {@link AlertsService} on
|
|
2444
|
+
* failure while the service retains the prior displayed state (Req 7.7, 13.7).
|
|
2445
|
+
* @param {string} meetingId - The meeting to log attendance for.
|
|
2446
|
+
* @return {void}
|
|
2447
|
+
* @memberof DashboardComponent
|
|
2448
|
+
*/
|
|
2449
|
+
onLogAttendance(meetingId) {
|
|
2450
|
+
this.dashboardService
|
|
2451
|
+
.logAttendance(meetingId)
|
|
2452
|
+
.pipe(takeUntil(this.destroy$))
|
|
2453
|
+
.subscribe({
|
|
2454
|
+
error: () => this.showAttendanceError(),
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
/**
|
|
2458
|
+
* Delegates a leave-meeting request to the service, surfacing the
|
|
2459
|
+
* attendance-action error message via the shared {@link AlertsService} on
|
|
2460
|
+
* failure while the service retains the prior displayed state (Req 7.8, 13.7).
|
|
2461
|
+
* @param {string} meetingId - The meeting to leave.
|
|
2462
|
+
* @return {void}
|
|
2463
|
+
* @memberof DashboardComponent
|
|
2464
|
+
*/
|
|
2465
|
+
onLeaveMeeting(meetingId) {
|
|
2466
|
+
this.dashboardService
|
|
2467
|
+
.leaveMeeting(meetingId)
|
|
2468
|
+
.pipe(takeUntil(this.destroy$))
|
|
2469
|
+
.subscribe({
|
|
2470
|
+
error: () => this.showAttendanceError(),
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* The route configuration in effect: the host-supplied `routePaths` when
|
|
2475
|
+
* provided, otherwise the default route config from `constants.json` so
|
|
2476
|
+
* navigation intents always carry valid targets (Req 11.1, 11.5).
|
|
2477
|
+
* @return {DashboardRouteConfig} The active route configuration.
|
|
2478
|
+
* @memberof DashboardComponent
|
|
2479
|
+
*/
|
|
2480
|
+
get activeRouteConfig() {
|
|
2481
|
+
return this.routePaths ?? this.constants.defaultRouteConfig;
|
|
2482
|
+
}
|
|
2483
|
+
/**
|
|
2484
|
+
* Subscribes to the service's state observables, mirroring each into a local
|
|
2485
|
+
* field for the template to bind. All subscriptions are torn down via
|
|
2486
|
+
* `takeUntil(destroy$)` (Req 13.1, 13.2, 13.5).
|
|
2487
|
+
* @return {void}
|
|
2488
|
+
* @memberof DashboardComponent
|
|
2489
|
+
*/
|
|
2490
|
+
subscribeToServiceState() {
|
|
2491
|
+
this.dashboardService.upcomingEvents$
|
|
2492
|
+
.pipe(takeUntil(this.destroy$))
|
|
2493
|
+
.subscribe((events) => (this.upcomingEvents = events));
|
|
2494
|
+
this.dashboardService.groups$
|
|
2495
|
+
.pipe(takeUntil(this.destroy$))
|
|
2496
|
+
.subscribe((groups) => {
|
|
2497
|
+
this.groups = groups;
|
|
2498
|
+
});
|
|
2499
|
+
this.dashboardService.upcomingState$
|
|
2500
|
+
.pipe(takeUntil(this.destroy$))
|
|
2501
|
+
.subscribe((state) => (this.upcomingState = state));
|
|
2502
|
+
this.dashboardService.groupsState$
|
|
2503
|
+
.pipe(takeUntil(this.destroy$))
|
|
2504
|
+
.subscribe((state) => (this.groupsState = state));
|
|
2505
|
+
this.dashboardService.attendanceStates$
|
|
2506
|
+
.pipe(takeUntil(this.destroy$))
|
|
2507
|
+
.subscribe((states) => (this.attendanceStates = states));
|
|
2508
|
+
this.dashboardService.inFlightMeetingIds$
|
|
2509
|
+
.pipe(takeUntil(this.destroy$))
|
|
2510
|
+
.subscribe((ids) => (this.inFlightMeetingIds = ids));
|
|
2511
|
+
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Subscribes to the Presentation_Library breakpoint observer to keep
|
|
2514
|
+
* `isMobileView` in sync with the viewport (Req 15.1, 15.2).
|
|
2515
|
+
* @return {void}
|
|
2516
|
+
* @memberof DashboardComponent
|
|
2517
|
+
*/
|
|
2518
|
+
subscribeToBreakpoint() {
|
|
2519
|
+
this.breakpointObserverService
|
|
2520
|
+
.getBreakpoint()
|
|
2521
|
+
.pipe(takeUntil(this.destroy$))
|
|
2522
|
+
.subscribe((result) => {
|
|
2523
|
+
this.isMobileView = result?.matches;
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
/**
|
|
2527
|
+
* Triggers the upcoming-events load, setting the section to `ERROR` on failure
|
|
2528
|
+
* so only the section error region renders (Req 13.1, 13.2, 13.5).
|
|
2529
|
+
* @return {void}
|
|
2530
|
+
* @memberof DashboardComponent
|
|
2531
|
+
*/
|
|
2532
|
+
loadUpcomingEvents() {
|
|
2533
|
+
this.dashboardService
|
|
2534
|
+
.loadUpcomingEvents()
|
|
2535
|
+
.pipe(takeUntil(this.destroy$))
|
|
2536
|
+
.subscribe({
|
|
2537
|
+
error: () => (this.upcomingState = DashboardSectionState.ERROR),
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Triggers the groups load, setting the section to `ERROR` on failure so only
|
|
2542
|
+
* the section error region renders. Isolated from the upcoming-events load so
|
|
2543
|
+
* one failing does not affect the other (Req 13.1, 13.2, 13.5).
|
|
2544
|
+
* @return {void}
|
|
2545
|
+
* @memberof DashboardComponent
|
|
2546
|
+
*/
|
|
2547
|
+
loadGroups() {
|
|
2548
|
+
this.dashboardService
|
|
2549
|
+
.loadGroups()
|
|
2550
|
+
.pipe(takeUntil(this.destroy$))
|
|
2551
|
+
.subscribe({
|
|
2552
|
+
error: () => (this.groupsState = DashboardSectionState.ERROR),
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Composes and emits a {@link DashboardNavigationIntent} for the host from the
|
|
2557
|
+
* resolved target path and an optional triggering id (Req 11.1).
|
|
2558
|
+
* @param {string} path - The resolved target route path.
|
|
2559
|
+
* @param {string} [id] - The triggering identifier, when applicable.
|
|
2560
|
+
* @return {void}
|
|
2561
|
+
* @memberof DashboardComponent
|
|
2562
|
+
*/
|
|
2563
|
+
emitNavigation(path, id) {
|
|
2564
|
+
this.dashboardNavigate.emit(id ? { path, id } : { path });
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Surfaces the attendance-action error message from `constants.json` via the
|
|
2568
|
+
* shared {@link AlertsService} (Req 13.7).
|
|
2569
|
+
* @return {void}
|
|
2570
|
+
* @memberof DashboardComponent
|
|
2571
|
+
*/
|
|
2572
|
+
showAttendanceError() {
|
|
2573
|
+
this.alertService?.showMessage({
|
|
2574
|
+
status: 'custom',
|
|
2575
|
+
message: this.constants?.attendance?.errorMessage ??
|
|
2576
|
+
'Unable to update your attendance. Please try again.',
|
|
2577
|
+
alertType: AlertType.ERROR,
|
|
2578
|
+
isCloseNeeded: true,
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardComponent, deps: [{ token: DashboardService }, { token: UserPermissionsService }, { token: i3.BreakpointObserverService }, { token: i1$1.AlertsService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2582
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DashboardComponent, isStandalone: true, selector: "ieeesa-dashboard", inputs: { routePaths: "routePaths", apiBaseURL: "apiBaseURL", userInfo: "userInfo", userPermissions: "userPermissions" }, outputs: { dashboardNavigate: "dashboardNavigate" }, providers: [AlertsService], viewQueries: [{ propertyName: "upcomingSection", first: true, predicate: ["upcomingSection"], descendants: true, read: ElementRef }, { propertyName: "groupsSection", first: true, predicate: ["groupsSection"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div\r\n class=\"ieeesa-dashboard\"\r\n [ngClass]=\"{ 'ieeesa-dashboard--mobile': isMobileView }\"\r\n>\r\n <ieeesa-dashboard-welcome-header\r\n class=\"ieeesa-dashboard__welcome\"\r\n [userName]=\"userInfo?.name ?? ''\"\r\n [meetingsCount]=\"meetingsCount\"\r\n [groupsCount]=\"groupsCount\"\r\n (shortcutSelected)=\"onJumpToShortcut($event)\"\r\n ></ieeesa-dashboard-welcome-header>\r\n\r\n <main class=\"ieeesa-dashboard__content\">\r\n <ieeesa-upcoming-meetings-events\r\n #upcomingSection\r\n class=\"ieeesa-dashboard__upcoming\"\r\n [(expanded)]=\"meetingsExpanded\"\r\n [events]=\"upcomingEvents\"\r\n [sectionState]=\"upcomingState\"\r\n [permissions]=\"attendancePermissions\"\r\n [attendanceStates]=\"attendanceStates\"\r\n [inFlightMeetingIds]=\"inFlightMeetingIds\"\r\n [isMobileView]=\"isMobileView\"\r\n (viewAll)=\"onViewAllEvents()\"\r\n (viewEvent)=\"onViewEvent($event)\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n (loadEventMeetings)=\"onLoadEventMeetings($event)\"\r\n ></ieeesa-upcoming-meetings-events>\r\n\r\n <ieeesa-your-groups\r\n #groupsSection\r\n [(expanded)]=\"groupsExpanded\"\r\n [groups]=\"groups\"\r\n [sectionState]=\"groupsState\"\r\n [totalGroups]=\"groups.length\"\r\n [pageIndex]=\"groupsPageIndex\"\r\n [pageSize]=\"groupsPageSize\"\r\n (viewAllGroups)=\"onViewAllGroups()\"\r\n (pageChange)=\"onGroupsPageChange($event)\"\r\n ></ieeesa-your-groups>\r\n </main>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-dashboard{display:flex;flex-direction:column;gap:24px;padding:16px;height:100vh;max-height:100vh;overflow:hidden}.ieeesa-dashboard__welcome{display:block;flex:0 0 auto}.ieeesa-dashboard__content{display:flex;flex-direction:column;gap:24px;flex:1 1 auto;overflow-y:auto;padding-right:4px}.ieeesa-dashboard__upcoming,.ieeesa-dashboard__groups,.ieeesa-dashboard__footer{display:block}.ieeesa-dashboard--mobile{padding:8px;gap:16px}.ieeesa-dashboard--mobile .ieeesa-dashboard__content{gap:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: UpcomingMeetingsEventsComponent, selector: "ieeesa-upcoming-meetings-events", inputs: ["events", "sectionState", "permissions", "attendanceStates", "inFlightMeetingIds", "isMobileView", "expanded"], outputs: ["viewAll", "viewEvent", "openMeeting", "logAttendance", "leaveMeeting", "meetingPageChange", "loadEventMeetings", "expandedChange"] }, { kind: "component", type: YourGroupsComponent, selector: "ieeesa-your-groups", inputs: ["groups", "sectionState", "totalGroups", "pageIndex", "pageSize", "expanded"], outputs: ["viewAllGroups", "pageChange", "expandedChange"] }, { kind: "component", type: DashboardWelcomeHeaderComponent, selector: "ieeesa-dashboard-welcome-header", inputs: ["userName", "meetingsCount", "groupsCount"], outputs: ["shortcutSelected"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
2583
|
+
}
|
|
2584
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
2585
|
+
type: Component,
|
|
2586
|
+
args: [{ selector: 'ieeesa-dashboard', standalone: true, imports: [
|
|
2587
|
+
CommonModule,
|
|
2588
|
+
UpcomingMeetingsEventsComponent,
|
|
2589
|
+
YourGroupsComponent,
|
|
2590
|
+
DashboardWelcomeHeaderComponent
|
|
2591
|
+
], encapsulation: ViewEncapsulation.None, providers: [AlertsService], template: "<div\r\n class=\"ieeesa-dashboard\"\r\n [ngClass]=\"{ 'ieeesa-dashboard--mobile': isMobileView }\"\r\n>\r\n <ieeesa-dashboard-welcome-header\r\n class=\"ieeesa-dashboard__welcome\"\r\n [userName]=\"userInfo?.name ?? ''\"\r\n [meetingsCount]=\"meetingsCount\"\r\n [groupsCount]=\"groupsCount\"\r\n (shortcutSelected)=\"onJumpToShortcut($event)\"\r\n ></ieeesa-dashboard-welcome-header>\r\n\r\n <main class=\"ieeesa-dashboard__content\">\r\n <ieeesa-upcoming-meetings-events\r\n #upcomingSection\r\n class=\"ieeesa-dashboard__upcoming\"\r\n [(expanded)]=\"meetingsExpanded\"\r\n [events]=\"upcomingEvents\"\r\n [sectionState]=\"upcomingState\"\r\n [permissions]=\"attendancePermissions\"\r\n [attendanceStates]=\"attendanceStates\"\r\n [inFlightMeetingIds]=\"inFlightMeetingIds\"\r\n [isMobileView]=\"isMobileView\"\r\n (viewAll)=\"onViewAllEvents()\"\r\n (viewEvent)=\"onViewEvent($event)\"\r\n (openMeeting)=\"onOpenMeeting($event)\"\r\n (logAttendance)=\"onLogAttendance($event)\"\r\n (leaveMeeting)=\"onLeaveMeeting($event)\"\r\n (loadEventMeetings)=\"onLoadEventMeetings($event)\"\r\n ></ieeesa-upcoming-meetings-events>\r\n\r\n <ieeesa-your-groups\r\n #groupsSection\r\n [(expanded)]=\"groupsExpanded\"\r\n [groups]=\"groups\"\r\n [sectionState]=\"groupsState\"\r\n [totalGroups]=\"groups.length\"\r\n [pageIndex]=\"groupsPageIndex\"\r\n [pageSize]=\"groupsPageSize\"\r\n (viewAllGroups)=\"onViewAllGroups()\"\r\n (pageChange)=\"onGroupsPageChange($event)\"\r\n ></ieeesa-your-groups>\r\n </main>\r\n</div>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-dashboard{display:flex;flex-direction:column;gap:24px;padding:16px;height:100vh;max-height:100vh;overflow:hidden}.ieeesa-dashboard__welcome{display:block;flex:0 0 auto}.ieeesa-dashboard__content{display:flex;flex-direction:column;gap:24px;flex:1 1 auto;overflow-y:auto;padding-right:4px}.ieeesa-dashboard__upcoming,.ieeesa-dashboard__groups,.ieeesa-dashboard__footer{display:block}.ieeesa-dashboard--mobile{padding:8px;gap:16px}.ieeesa-dashboard--mobile .ieeesa-dashboard__content{gap:16px}\n"] }]
|
|
2592
|
+
}], ctorParameters: function () { return [{ type: DashboardService }, { type: UserPermissionsService }, { type: i3.BreakpointObserverService }, { type: i1$1.AlertsService }]; }, propDecorators: { routePaths: [{
|
|
2593
|
+
type: Input
|
|
2594
|
+
}], apiBaseURL: [{
|
|
2595
|
+
type: Input
|
|
2596
|
+
}], userInfo: [{
|
|
2597
|
+
type: Input
|
|
2598
|
+
}], userPermissions: [{
|
|
2599
|
+
type: Input
|
|
2600
|
+
}], dashboardNavigate: [{
|
|
2601
|
+
type: Output
|
|
2602
|
+
}], upcomingSection: [{
|
|
2603
|
+
type: ViewChild,
|
|
2604
|
+
args: ['upcomingSection', { read: ElementRef }]
|
|
2605
|
+
}], groupsSection: [{
|
|
2606
|
+
type: ViewChild,
|
|
2607
|
+
args: ['groupsSection', { read: ElementRef }]
|
|
2608
|
+
}] } });
|
|
2609
|
+
|
|
2610
|
+
var dashboard_component = /*#__PURE__*/Object.freeze({
|
|
2611
|
+
__proto__: null,
|
|
2612
|
+
DashboardComponent: DashboardComponent
|
|
2613
|
+
});
|
|
2614
|
+
|
|
2615
|
+
/**
|
|
2616
|
+
* Member_Level_Badge renders a single member-level value as a colored pill.
|
|
2617
|
+
* It reuses the Presentation_Library Legend component for the pill primitive,
|
|
2618
|
+
* sourcing the level-to-color mapping from `constants.json` (`memberLevel.colorMap`)
|
|
2619
|
+
* with a nullish-coalescing fallback to the configured default color.
|
|
2620
|
+
* @export
|
|
2621
|
+
* @class MemberLevelBadgeComponent
|
|
2622
|
+
*/
|
|
2623
|
+
class MemberLevelBadgeComponent {
|
|
2624
|
+
constructor() {
|
|
2625
|
+
this.constants = constants$1;
|
|
2626
|
+
this.memberLevelValue = '';
|
|
2627
|
+
/** The Legend input consumed by the Presentation_Library Legend component. */
|
|
2628
|
+
this.legends = this.buildLegends('');
|
|
2629
|
+
}
|
|
2630
|
+
set memberLevel(value) {
|
|
2631
|
+
this.memberLevelValue = value ?? '';
|
|
2632
|
+
this.legends = this.buildLegends(this.memberLevelValue);
|
|
2633
|
+
}
|
|
2634
|
+
get memberLevel() {
|
|
2635
|
+
return this.memberLevelValue;
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* Builds the single-item Legend list for the supplied member level, resolving
|
|
2639
|
+
* the pill color from the `constants.json` color map and falling back to the
|
|
2640
|
+
* configured default color when the level has no explicit mapping.
|
|
2641
|
+
* @param {string} memberLevel - The member-level label to render.
|
|
2642
|
+
* @return {Legend[]} A single-element Legend array for the Legend component.
|
|
2643
|
+
* @memberof MemberLevelBadgeComponent
|
|
2644
|
+
*/
|
|
2645
|
+
buildLegends(memberLevel) {
|
|
2646
|
+
return [
|
|
2647
|
+
{
|
|
2648
|
+
label: memberLevel,
|
|
2649
|
+
color: this.resolveColorClass(memberLevel),
|
|
2650
|
+
hierarchy: 0,
|
|
2651
|
+
},
|
|
2652
|
+
];
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Resolves the CSS modifier class for a member level from the `constants.json`
|
|
2656
|
+
* color map, using the `??` fallback to the `default` entry when the level is
|
|
2657
|
+
* missing from the map.
|
|
2658
|
+
* @param {string} memberLevel - The member-level label to resolve a color for.
|
|
2659
|
+
* @return {string} The CSS modifier class applied to the pill.
|
|
2660
|
+
* @memberof MemberLevelBadgeComponent
|
|
2661
|
+
*/
|
|
2662
|
+
resolveColorClass(memberLevel) {
|
|
2663
|
+
const colorMap = this.constants?.memberLevel?.colorMap;
|
|
2664
|
+
const token = colorMap?.[memberLevel] ?? colorMap?.['default'] ?? '$ieeesa-color-neutral';
|
|
2665
|
+
return this.toColorClass(token);
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Converts a shared-styles color token (for example `$ieeesa-color-success`)
|
|
2669
|
+
* into a valid BEM-style CSS modifier class defined in this component's SCSS.
|
|
2670
|
+
* @param {string} token - The color token from the color map.
|
|
2671
|
+
* @return {string} A valid CSS class name.
|
|
2672
|
+
* @memberof MemberLevelBadgeComponent
|
|
2673
|
+
*/
|
|
2674
|
+
toColorClass(token) {
|
|
2675
|
+
const normalized = token.replace(/^\$ieeesa-color-/, '').replace(/^\$/, '');
|
|
2676
|
+
return `ieeesa-member-level-badge--${normalized || 'neutral'}`;
|
|
2677
|
+
}
|
|
2678
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MemberLevelBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2679
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MemberLevelBadgeComponent, isStandalone: true, selector: "ieeesa-member-level-badge", inputs: { memberLevel: "memberLevel" }, ngImport: i0, template: "<span\r\n class=\"ieeesa-member-level-badge\"\r\n [attr.aria-label]=\"memberLevel\"\r\n>\r\n <ieeesa-legend\r\n *ngIf=\"memberLevel\"\r\n [legends]=\"legends\"\r\n ></ieeesa-legend>\r\n</span>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-member-level-badge,.ieeesa-member-level-badge .ieeesa-legend{display:inline-flex}.ieeesa-member-level-badge .ieeesa-legend__indicator{align-items:center;gap:4px;padding:4px 12px;border-radius:16px;background-color:#f0f5f9}.ieeesa-member-level-badge .ieeesa-legend__square{width:8px;min-width:8px;height:8px;margin:0;border-radius:50%}.ieeesa-member-level-badge .ieeesa-legend p{margin:0}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--success{background-color:#78d7ef}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--info{background-color:#00b5e2}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--warning{background-color:#ffd92e}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--primary{background-color:#00629b}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--neutral{background-color:#939094}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LegendComponent, selector: "ieeesa-legend", inputs: ["legends", "isSorting"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
2680
|
+
}
|
|
2681
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MemberLevelBadgeComponent, decorators: [{
|
|
2682
|
+
type: Component,
|
|
2683
|
+
args: [{ selector: 'ieeesa-member-level-badge', standalone: true, imports: [CommonModule, LegendComponent], encapsulation: ViewEncapsulation.None, template: "<span\r\n class=\"ieeesa-member-level-badge\"\r\n [attr.aria-label]=\"memberLevel\"\r\n>\r\n <ieeesa-legend\r\n *ngIf=\"memberLevel\"\r\n [legends]=\"legends\"\r\n ></ieeesa-legend>\r\n</span>\r\n", styles: [".ieeesa-subtitle{text-align:left;font-family:Calibri Regular;font-size:1.5625rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-body{text-align:left;font-family:Calibri Regular;font-size:1.25rem;letter-spacing:0;color:#000;opacity:1}.ieeesa-display-lg-57{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:3.5625rem;line-height:64px;color:#000;letter-spacing:0}.ieeesa-display-md-45{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.813rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-md-47{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.9375rem;line-height:52px;color:#000;letter-spacing:0}.ieeesa-display-sm-38{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.375rem;line-height:44px;color:#000;letter-spacing:0}.ieeesa-headline-lg-32{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-lg-34{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:2.125rem;line-height:40px;color:#000;letter-spacing:0}.ieeesa-headline-md-30{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.875rem;line-height:36px;color:#000;letter-spacing:0}.ieeesa-headline-sm-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:32px;color:#00629b;letter-spacing:0}.ieeesa-headline-sm-26{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.625rem;line-height:32px;color:#000;letter-spacing:0}.ieeesa-title-lg-bold-24{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-lg-24{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.5rem;line-height:28px;color:#000;letter-spacing:0}.ieeesa-title-md-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.009375em}.ieeesa-title-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-title-sm-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-label-lg-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.ieeesa-btn-label-lg-bold-16{font-family:Calibri Regular;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#00629b;letter-spacing:.00625em}.ieeesa-label-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-label-sm-13{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.8125rem;line-height:16px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-16{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-bold-18{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-lg-18{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1.125rem;line-height:24px;color:#000;letter-spacing:.03125em}.ieeesa-body-md-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:20px;color:#1c1b1f;letter-spacing:.015625em}.ieeesa-body-md-16{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:20px;color:#000;letter-spacing:.015625em}.ieeesa-body-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-sm-12{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.75rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-body-color-sm-14{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:.875rem;line-height:18px;color:#49454f;letter-spacing:.025em}.ieeesa-body-sm-bold-14{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:.875rem;line-height:16px;color:#000;letter-spacing:.025em}.ieeesa-title-inter-lg-bold-24{font-family:Inter Bold;font-style:normal;font-weight:700;font-size:1.5rem;line-height:29px;color:#000;letter-spacing:0}.mat-mdc-button.mat-mdc-button-base.mat-primary-button,.mat-mdc-button.mat-mdc-button-base.mat-secondary-button,.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button,.mat-mdc-button.mat-mdc-button-base.mat-text-button{min-width:103px;width:auto;min-height:40px;height:auto;border-radius:3px;text-align:center;padding:.625em 1.5em;border:none;font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#000;letter-spacing:.00625em}.mat-mdc-button.mat-mdc-button-base>.mat-icon{margin-right:11px}.mat-mdc-button.mat-mdc-button-base.mat-primary-button{background-color:#00629b;color:#fff}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:focus{background:#1f75a7}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:hover{background-color:#003e65}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:active{background-color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-primary-button:disabled{background-color:#1c1b1f1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button{color:#fff;background:#a7a8aa;box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:hover{background:#a7a8aa}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:focus{background:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:active{background:#1d192b1f}.mat-mdc-button.mat-mdc-button-base.mat-secondary-button:disabled{background:#1c1b1f1f;color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button{background-color:#fff;border:1px solid #00629b;color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:hover{background-color:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:focus{background-color:#f0f5f9}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:active{background:#6750a41f}.mat-mdc-button.mat-mdc-button-base.mat-tertiary-button:disabled{border:1px solid rgba(28,27,31,.12);color:#1c1b1f;opacity:.38}.mat-mdc-button.mat-mdc-button-base.mat-text-button{color:#00629b}.mat-mdc-button.mat-mdc-button-base.mat-text-button:hover,.mat-mdc-button.mat-mdc-button-base.mat-text-button:active{background:#6750a414}.mat-mdc-button.mat-mdc-button-base.mat-text-button:disabled{color:#1c1b1f;opacity:.38}.ieeesa-text-button{color:#cac4d0;background:none;border:none}.ieeesa-view-more-or-less-button{border:none;background:none;text-decoration:underline;color:#00629b}.flex-align-center{display:flex;align-items:center;justify-content:center}.mat-button-toggle-checked{background-color:#a7a8aa}.mat-button-toggle-checked .mat-button-toggle-label-content:before{font-family:\"Font Awesome 5 Free\";font-weight:900;content:\"\\f00c\";padding-right:.5625em}.mat-button-toggle-group .mat-button-toggle-label-content{font-family:Calibri Bold;font-style:normal;font-weight:700;font-size:1rem;line-height:20px;color:#1c1b1f;letter-spacing:.00625em}.no-bg-color-btn{color:#00629b;border-radius:3px;border:1px solid #00629b;min-height:40px;height:auto}@media (max-width: 768px){.mat-button-toggle-group .mat-button-toggle-label-content{max-width:8ch;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;position:relative}}.cdk-overlay-pane .mat-mdc-tooltip .mdc-tooltip__surface{color:#525252;padding:6px 12px;font-family:Calibri Regular;font-size:1rem;border:1px solid #cac4d0;background:#fff;box-shadow:0 4px 8px #00000040;max-width:unset!important}.cdk-overlay-pane .mat-mdc-option .mdc-list-item__primary-text{font-family:Calibri Regular!important}.cdk-overlay-pane.ieeesa-modal-confirm-dialog,.cdk-overlay-pane.ieeesa-modal-dialog,.cdk-overlay-pane.ieeesa-alert-dialog{width:100%;min-width:312px}.mat-mdc-form-field{font-family:Calibri Regular;font-style:normal;font-weight:400;font-size:1rem;line-height:24px;color:#49454f;letter-spacing:.03125em}.ieeesa-cancel-modal-confirm-dialog{width:25vw!important}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation{padding:1.5em 1.5em 1em}.ieeesa-cancel-modal-confirm-dialog .ieeesa-confirmation .mat-mdc-dialog-content{text-align:center;padding:0 0 1em!important}.mat-mdc-button,.mat-mdc-outlined-button{--mat-mdc-button-persistent-ripple-color: unset}@media (max-width: 768px){.ieeesa-cancel-modal-confirm-dialog{width:90vw!important}}.ieeesa-wrapper-border{border:1px solid #b2b7be;border-top:none;padding:1.5em;border-radius:0 0 4px 4px}.ieeesa-member-level-badge,.ieeesa-member-level-badge .ieeesa-legend{display:inline-flex}.ieeesa-member-level-badge .ieeesa-legend__indicator{align-items:center;gap:4px;padding:4px 12px;border-radius:16px;background-color:#f0f5f9}.ieeesa-member-level-badge .ieeesa-legend__square{width:8px;min-width:8px;height:8px;margin:0;border-radius:50%}.ieeesa-member-level-badge .ieeesa-legend p{margin:0}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--success{background-color:#78d7ef}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--info{background-color:#00b5e2}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--warning{background-color:#ffd92e}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--primary{background-color:#00629b}.ieeesa-member-level-badge .ieeesa-legend__square.ieeesa-member-level-badge--neutral{background-color:#939094}\n"] }]
|
|
2684
|
+
}], propDecorators: { memberLevel: [{
|
|
2685
|
+
type: Input
|
|
2686
|
+
}] } });
|
|
2687
|
+
|
|
2688
|
+
class DashboardModule {
|
|
2689
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2690
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: DashboardModule, imports: [DashboardComponent], exports: [DashboardComponent] }); }
|
|
2691
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardModule, imports: [DashboardComponent] }); }
|
|
2692
|
+
}
|
|
2693
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DashboardModule, decorators: [{
|
|
2694
|
+
type: NgModule,
|
|
2695
|
+
args: [{
|
|
2696
|
+
imports: [DashboardComponent],
|
|
2697
|
+
exports: [DashboardComponent],
|
|
2698
|
+
}]
|
|
2699
|
+
}] });
|
|
2700
|
+
|
|
2701
|
+
const DASHBOARD_ROUTES = [
|
|
2702
|
+
{
|
|
2703
|
+
path: '',
|
|
2704
|
+
loadComponent: () => Promise.resolve().then(function () { return dashboard_component; }).then((m) => m.DashboardComponent),
|
|
2705
|
+
},
|
|
2706
|
+
];
|
|
2707
|
+
|
|
2708
|
+
/**
|
|
2709
|
+
* Request payloads for the dashboard "events & meetings" backend calls. These
|
|
2710
|
+
* mirror the `events-and-meetings` library's `GetEventsAndMeetingsPayload` /
|
|
2711
|
+
* `GetMeetingsByEventIdPayload` so the dashboard reuses the exact contract the
|
|
2712
|
+
* existing `view-events-meetings-list` screen posts.
|
|
2713
|
+
*/
|
|
2714
|
+
|
|
2715
|
+
const DashboardRoutePathsMock = {
|
|
2716
|
+
eventDetail: 'events-and-meetings/view-event',
|
|
2717
|
+
meetingDetail: 'events-and-meetings/view-meeting',
|
|
2718
|
+
/*
|
|
2719
|
+
* The demo app only registers a flat `groups` route (no group-detail screen),
|
|
2720
|
+
* so group-row navigation targets it rather than a `view-group` child that the
|
|
2721
|
+
* demo does not implement. A consuming app with a real group-detail route
|
|
2722
|
+
* supplies its own path via the `routePaths` input.
|
|
2723
|
+
*/
|
|
2724
|
+
groupDetail: 'groups',
|
|
2725
|
+
viewAllEvents: 'events-and-meetings/view-events-meetings-list',
|
|
2726
|
+
viewAllGroups: 'groups',
|
|
2727
|
+
};
|
|
2728
|
+
|
|
2729
|
+
const DashboardUserPermissionsMock = [
|
|
2730
|
+
{
|
|
2731
|
+
permissionName: 'View Events',
|
|
2732
|
+
permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',
|
|
2733
|
+
},
|
|
2734
|
+
{
|
|
2735
|
+
permissionName: 'View Meetings',
|
|
2736
|
+
permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',
|
|
2737
|
+
},
|
|
2738
|
+
{
|
|
2739
|
+
permissionName: 'View Groups',
|
|
2740
|
+
permissionId: 'PERM_9a1f0c84-2b77-4e2a-9f3d-1c6b4e9a8d20',
|
|
2741
|
+
},
|
|
2742
|
+
{
|
|
2743
|
+
permissionName: 'Log Attendance',
|
|
2744
|
+
permissionId: 'PERM_1b2c3d4e-5f60-4718-8293-aabbccddeeff',
|
|
2745
|
+
},
|
|
2746
|
+
{
|
|
2747
|
+
permissionName: 'Leave Meeting',
|
|
2748
|
+
permissionId: 'PERM_6f5e4d3c-2b1a-4908-8716-ffeeddccbbaa',
|
|
2749
|
+
},
|
|
2750
|
+
];
|
|
2751
|
+
|
|
2752
|
+
/**
|
|
2753
|
+
* Mock upcoming-events + groups fixtures for the dashboard library.
|
|
2754
|
+
*
|
|
2755
|
+
* These exercise the key presentation edge cases:
|
|
2756
|
+
* - empty/undefined `groupOrCommittee` and `roomOrLocation` (empty-field placeholder)
|
|
2757
|
+
* - a mix of `CURRENTLY_ATTENDING` / `NOT_ATTENDING` attendance states
|
|
2758
|
+
* - events with many meetings so per-card pagination is exercised
|
|
2759
|
+
*
|
|
2760
|
+
* TODO: Replace mock with real API call when BE is ready
|
|
2761
|
+
*/
|
|
2762
|
+
const DashboardUpcomingEventsMock = [
|
|
2763
|
+
{
|
|
2764
|
+
eventId: 'EVT-001',
|
|
2765
|
+
kind: UpcomingItemKind.EVENT,
|
|
2766
|
+
title: 'NESC Revision Cycle Kickoff',
|
|
2767
|
+
status: 'In Progress',
|
|
2768
|
+
dayIndicator: 'Day 1 of 3',
|
|
2769
|
+
meetingCount: 6,
|
|
2770
|
+
openForAttendanceCount: 3,
|
|
2771
|
+
startDate: '2025-03-14T09:00:00',
|
|
2772
|
+
endDate: '2025-03-16T17:00:00',
|
|
2773
|
+
timezone: 'America/New_York',
|
|
2774
|
+
meetings: [
|
|
2775
|
+
{
|
|
2776
|
+
meetingId: 'MTG-001',
|
|
2777
|
+
meetingName: 'Opening Plenary',
|
|
2778
|
+
groupOrCommittee: 'NESC Main Committee',
|
|
2779
|
+
roomOrLocation: 'Grand Ballroom A',
|
|
2780
|
+
meetingDate: '2025-03-14T09:00:00',
|
|
2781
|
+
meetingTime: '2025-03-14T09:00:00',
|
|
2782
|
+
timezone: 'America/New_York',
|
|
2783
|
+
isOpenForAttendance: true,
|
|
2784
|
+
attendanceState: AttendanceState.CURRENTLY_ATTENDING,
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
meetingId: 'MTG-002',
|
|
2788
|
+
meetingName: 'Subcommittee 1 Working Session',
|
|
2789
|
+
groupOrCommittee: 'Subcommittee 1 - Grounding',
|
|
2790
|
+
// RoomOrLocation intentionally omitted to exercise the empty-field placeholder.
|
|
2791
|
+
meetingDate: '2025-03-14T11:00:00',
|
|
2792
|
+
meetingTime: '2025-03-14T11:00:00',
|
|
2793
|
+
timezone: 'America/New_York',
|
|
2794
|
+
isOpenForAttendance: true,
|
|
2795
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2796
|
+
},
|
|
2797
|
+
{
|
|
2798
|
+
meetingId: 'MTG-003',
|
|
2799
|
+
meetingName: 'Subcommittee 2 Working Session',
|
|
2800
|
+
// GroupOrCommittee intentionally empty to exercise the empty-field placeholder.
|
|
2801
|
+
groupOrCommittee: '',
|
|
2802
|
+
roomOrLocation: 'Room 204',
|
|
2803
|
+
meetingDate: '2025-03-14T13:30:00',
|
|
2804
|
+
meetingTime: '2025-03-14T13:30:00',
|
|
2805
|
+
timezone: 'America/New_York',
|
|
2806
|
+
isOpenForAttendance: true,
|
|
2807
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2808
|
+
},
|
|
2809
|
+
{
|
|
2810
|
+
meetingId: 'MTG-004',
|
|
2811
|
+
meetingName: 'Editorial Review',
|
|
2812
|
+
groupOrCommittee: 'Editorial Task Force',
|
|
2813
|
+
roomOrLocation: 'Room 118',
|
|
2814
|
+
meetingDate: '2025-03-15T09:00:00',
|
|
2815
|
+
meetingTime: '2025-03-15T09:00:00',
|
|
2816
|
+
timezone: 'America/New_York',
|
|
2817
|
+
isOpenForAttendance: false,
|
|
2818
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2819
|
+
},
|
|
2820
|
+
{
|
|
2821
|
+
meetingId: 'MTG-005',
|
|
2822
|
+
meetingName: 'Interpretations Panel',
|
|
2823
|
+
groupOrCommittee: 'Interpretations Subcommittee',
|
|
2824
|
+
roomOrLocation: 'Room 310',
|
|
2825
|
+
meetingDate: '2025-03-15T14:00:00',
|
|
2826
|
+
meetingTime: '2025-03-15T14:00:00',
|
|
2827
|
+
timezone: 'America/New_York',
|
|
2828
|
+
isOpenForAttendance: true,
|
|
2829
|
+
attendanceState: AttendanceState.CURRENTLY_ATTENDING,
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
meetingId: 'MTG-006',
|
|
2833
|
+
meetingName: 'Closing Plenary',
|
|
2834
|
+
groupOrCommittee: 'NESC Main Committee',
|
|
2835
|
+
roomOrLocation: 'Grand Ballroom A',
|
|
2836
|
+
meetingDate: '2025-03-16T15:00:00',
|
|
2837
|
+
meetingTime: '2025-03-16T15:00:00',
|
|
2838
|
+
timezone: 'America/New_York',
|
|
2839
|
+
isOpenForAttendance: false,
|
|
2840
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2841
|
+
},
|
|
2842
|
+
],
|
|
2843
|
+
},
|
|
2844
|
+
{
|
|
2845
|
+
eventId: 'EVT-002',
|
|
2846
|
+
kind: UpcomingItemKind.EVENT,
|
|
2847
|
+
title: 'Standards Board Quarterly Meeting',
|
|
2848
|
+
status: 'Upcoming',
|
|
2849
|
+
dayIndicator: 'Day 1 of 1',
|
|
2850
|
+
meetingCount: 3,
|
|
2851
|
+
openForAttendanceCount: 1,
|
|
2852
|
+
startDate: '2025-04-02T08:30:00',
|
|
2853
|
+
endDate: '2025-04-02T16:00:00',
|
|
2854
|
+
timezone: 'America/Los_Angeles',
|
|
2855
|
+
meetings: [
|
|
2856
|
+
{
|
|
2857
|
+
meetingId: 'MTG-101',
|
|
2858
|
+
meetingName: 'Board Opening Remarks',
|
|
2859
|
+
groupOrCommittee: 'Standards Board',
|
|
2860
|
+
roomOrLocation: 'Pacific Hall',
|
|
2861
|
+
meetingDate: '2025-04-02T08:30:00',
|
|
2862
|
+
meetingTime: '2025-04-02T08:30:00',
|
|
2863
|
+
timezone: 'America/Los_Angeles',
|
|
2864
|
+
isOpenForAttendance: true,
|
|
2865
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2866
|
+
},
|
|
2867
|
+
{
|
|
2868
|
+
meetingId: 'MTG-102',
|
|
2869
|
+
meetingName: 'Ballot Review Session',
|
|
2870
|
+
// Both optional location/group fields omitted to exercise placeholders.
|
|
2871
|
+
meetingDate: '2025-04-02T10:30:00',
|
|
2872
|
+
meetingTime: '2025-04-02T10:30:00',
|
|
2873
|
+
timezone: 'America/Los_Angeles',
|
|
2874
|
+
isOpenForAttendance: false,
|
|
2875
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2876
|
+
},
|
|
2877
|
+
{
|
|
2878
|
+
meetingId: 'MTG-103',
|
|
2879
|
+
meetingName: 'Action Items & Wrap-up',
|
|
2880
|
+
groupOrCommittee: 'Standards Board',
|
|
2881
|
+
roomOrLocation: 'Pacific Hall',
|
|
2882
|
+
meetingDate: '2025-04-02T15:00:00',
|
|
2883
|
+
meetingTime: '2025-04-02T15:00:00',
|
|
2884
|
+
timezone: 'America/Los_Angeles',
|
|
2885
|
+
isOpenForAttendance: false,
|
|
2886
|
+
attendanceState: AttendanceState.CURRENTLY_ATTENDING,
|
|
2887
|
+
},
|
|
2888
|
+
],
|
|
2889
|
+
},
|
|
2890
|
+
{
|
|
2891
|
+
eventId: 'EVT-003',
|
|
2892
|
+
kind: UpcomingItemKind.EVENT,
|
|
2893
|
+
title: 'Working Group Interim',
|
|
2894
|
+
status: 'Upcoming',
|
|
2895
|
+
// DayIndicator intentionally omitted (optional field).
|
|
2896
|
+
meetingCount: 0,
|
|
2897
|
+
openForAttendanceCount: 0,
|
|
2898
|
+
startDate: '2025-05-20T09:00:00',
|
|
2899
|
+
endDate: '2025-05-20T12:00:00',
|
|
2900
|
+
timezone: 'Europe/London',
|
|
2901
|
+
meetings: [],
|
|
2902
|
+
},
|
|
2903
|
+
];
|
|
2904
|
+
/**
|
|
2905
|
+
* Mock a single meeting row with an empty `meetingId` to exercise the
|
|
2906
|
+
* non-actionable (empty/undefined id) path in the meeting row component.
|
|
2907
|
+
*
|
|
2908
|
+
* TODO: Replace mock with real API call when BE is ready
|
|
2909
|
+
*/
|
|
2910
|
+
const DashboardNonActionableMeetingMock = {
|
|
2911
|
+
meetingId: '',
|
|
2912
|
+
meetingName: 'Unscheduled Placeholder Session',
|
|
2913
|
+
groupOrCommittee: '',
|
|
2914
|
+
meetingDate: '2025-06-01T09:00:00',
|
|
2915
|
+
meetingTime: '2025-06-01T09:00:00',
|
|
2916
|
+
timezone: 'America/New_York',
|
|
2917
|
+
isOpenForAttendance: false,
|
|
2918
|
+
attendanceState: AttendanceState.NOT_ATTENDING,
|
|
2919
|
+
};
|
|
2920
|
+
/**
|
|
2921
|
+
* Mock groups fixtures for the dashboard "Your Groups" section.
|
|
2922
|
+
*
|
|
2923
|
+
* Includes rows with missing optional fields (`type`, `officerRole`,
|
|
2924
|
+
* `affiliation`) and a spread of member levels so the member-level badge
|
|
2925
|
+
* colour map and empty-field placeholders are exercised.
|
|
2926
|
+
*
|
|
2927
|
+
* TODO: Replace mock with real API call when BE is ready
|
|
2928
|
+
*/
|
|
2929
|
+
const DashboardGroupsMock = [
|
|
2930
|
+
{
|
|
2931
|
+
groupId: 'GRP-001',
|
|
2932
|
+
group: 'NESC Main Committee',
|
|
2933
|
+
type: 'Committee',
|
|
2934
|
+
officerRole: 'Chair',
|
|
2935
|
+
affiliation: 'Employer Corp',
|
|
2936
|
+
memberLevel: 'Senior Member',
|
|
2937
|
+
},
|
|
2938
|
+
{
|
|
2939
|
+
groupId: 'GRP-002',
|
|
2940
|
+
group: 'Subcommittee 1 - Grounding',
|
|
2941
|
+
type: 'Subcommittee',
|
|
2942
|
+
// OfficerRole intentionally omitted (member with no officer role).
|
|
2943
|
+
affiliation: 'Standards Member',
|
|
2944
|
+
memberLevel: 'Member',
|
|
2945
|
+
},
|
|
2946
|
+
{
|
|
2947
|
+
groupId: 'GRP-003',
|
|
2948
|
+
group: 'Editorial Task Force',
|
|
2949
|
+
// Type and affiliation intentionally omitted to exercise placeholders.
|
|
2950
|
+
officerRole: 'Secretary',
|
|
2951
|
+
memberLevel: 'Fellow',
|
|
2952
|
+
},
|
|
2953
|
+
{
|
|
2954
|
+
groupId: 'GRP-004',
|
|
2955
|
+
group: 'Interpretations Subcommittee',
|
|
2956
|
+
type: 'Subcommittee',
|
|
2957
|
+
officerRole: 'Member',
|
|
2958
|
+
affiliation: 'Tech Solutions Inc',
|
|
2959
|
+
memberLevel: 'Associate Member',
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
groupId: 'GRP-005',
|
|
2963
|
+
group: 'Standards Board',
|
|
2964
|
+
type: 'Board',
|
|
2965
|
+
officerRole: 'Vice Chair',
|
|
2966
|
+
affiliation: 'CodeCraft Studio',
|
|
2967
|
+
memberLevel: 'Senior Member',
|
|
2968
|
+
},
|
|
2969
|
+
];
|
|
2970
|
+
|
|
2971
|
+
/*
|
|
2972
|
+
* Public API Surface of dashboard
|
|
2973
|
+
*/
|
|
2974
|
+
// Container component + navigation intent type (DashboardComponent, DashboardNavigationIntent)
|
|
2975
|
+
|
|
2976
|
+
/**
|
|
2977
|
+
* Generated bundle index. Do not edit.
|
|
2978
|
+
*/
|
|
2979
|
+
|
|
2980
|
+
export { AttendanceState, DASHBOARD_ROUTES, DashboardComponent, DashboardGroupsMock, DashboardJumpTarget, DashboardModule, DashboardNonActionableMeetingMock, DashboardPermissionType, DashboardRoutePathsMock, DashboardSectionState, DashboardService, DashboardUpcomingEventsMock, DashboardUserPermissionsMock, DashboardWelcomeHeaderComponent, EventGroupCardComponent, MeetingAttendanceRowComponent, MemberLevelBadgeComponent, UpcomingItemKind, UpcomingMeetingsEventsComponent, UserPermissionsService, YourGroupsComponent };
|
|
2981
|
+
//# sourceMappingURL=ieeesa-npm-dashboard.mjs.map
|