@ieeesa-npm/dashboard 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/assets/constants.json +7 -3
- package/esm2022/lib/components/event-group-card/event-group-card.component.mjs +99 -13
- package/esm2022/lib/components/meeting-attendance-row/meeting-attendance-row.component.mjs +101 -23
- package/esm2022/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.mjs +66 -6
- package/esm2022/lib/components/your-groups/your-groups.component.mjs +3 -3
- package/esm2022/lib/dashboard.component.mjs +63 -12
- package/esm2022/lib/models/attendance-state.model.mjs +8 -1
- package/esm2022/lib/models/dashboard-route-config.model.mjs +1 -1
- package/esm2022/lib/models/event-meeting-list-item.model.mjs +1 -1
- package/esm2022/lib/models/event-meeting-list-payload.model.mjs +7 -5
- package/esm2022/lib/models/meeting-row.model.mjs +1 -1
- package/esm2022/lib/models/upcoming-event.model.mjs +1 -1
- package/esm2022/lib/services/dashboard.service.mjs +71 -126
- package/esm2022/lib/services/user-permissions.service.mjs +23 -9
- package/esm2022/lib/utils/event-meeting-mapper.util.mjs +47 -41
- package/fesm2022/ieeesa-npm-dashboard.mjs +490 -289
- package/fesm2022/ieeesa-npm-dashboard.mjs.map +1 -1
- package/lib/components/event-group-card/event-group-card.component.d.ts +73 -6
- package/lib/components/meeting-attendance-row/meeting-attendance-row.component.d.ts +61 -7
- package/lib/components/member-level-badge/member-level-badge.component.d.ts +12 -1
- package/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.d.ts +49 -3
- package/lib/dashboard.component.d.ts +39 -6
- package/lib/models/attendance-state.model.d.ts +8 -1
- package/lib/models/dashboard-route-config.model.d.ts +14 -0
- package/lib/models/event-meeting-list-item.model.d.ts +68 -68
- package/lib/models/event-meeting-list-payload.model.d.ts +14 -25
- package/lib/models/meeting-row.model.d.ts +2 -0
- package/lib/models/upcoming-event.model.d.ts +9 -0
- package/lib/services/dashboard.service.d.ts +25 -53
- package/lib/services/user-permissions.service.d.ts +8 -4
- package/lib/utils/event-meeting-mapper.util.d.ts +15 -21
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ieeesa-npm-dashboard.mjs","sources":["../../../projects/dashboard/src/lib/models/dashboard-section-state.model.ts","../../../projects/dashboard/src/lib/models/attendance-state.model.ts","../../../projects/dashboard/src/lib/models/upcoming-event.model.ts","../../../projects/dashboard/src/lib/assets/date-formats.ts","../../../projects/dashboard/src/lib/utils/attendance-action.util.ts","../../../projects/dashboard/src/lib/utils/date-format.util.ts","../../../projects/dashboard/src/lib/components/meeting-attendance-row/meeting-attendance-row.component.ts","../../../projects/dashboard/src/lib/components/meeting-attendance-row/meeting-attendance-row.component.html","../../../projects/dashboard/src/lib/components/event-group-card/event-group-card.component.ts","../../../projects/dashboard/src/lib/components/event-group-card/event-group-card.component.html","../../../projects/dashboard/src/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.ts","../../../projects/dashboard/src/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.html","../../../projects/dashboard/src/lib/components/welcome-header/dashboard-welcome-header.component.ts","../../../projects/dashboard/src/lib/components/welcome-header/dashboard-welcome-header.component.html","../../../projects/dashboard/src/lib/components/your-groups/your-groups.component.ts","../../../projects/dashboard/src/lib/components/your-groups/your-groups.component.html","../../../projects/dashboard/src/lib/utils/event-meeting-mapper.util.ts","../../../projects/dashboard/src/lib/services/attendance-reducers.ts","../../../projects/dashboard/src/lib/services/dashboard.service.ts","../../../projects/dashboard/src/lib/services/user-permissions.service.ts","../../../projects/dashboard/src/lib/dashboard.component.ts","../../../projects/dashboard/src/lib/dashboard.component.html","../../../projects/dashboard/src/lib/components/member-level-badge/member-level-badge.component.ts","../../../projects/dashboard/src/lib/components/member-level-badge/member-level-badge.component.html","../../../projects/dashboard/src/lib/dashboard.module.ts","../../../projects/dashboard/src/lib/dashboard.routes.ts","../../../projects/dashboard/src/lib/models/event-meeting-list-payload.model.ts","../../../projects/dashboard/src/lib/assets/dashboard-route-paths.mock.ts","../../../projects/dashboard/src/lib/assets/dashboard-user-permissions.mock.ts","../../../projects/dashboard/src/lib/assets/dashboard-mock.ts","../../../projects/dashboard/src/public-api.ts","../../../projects/dashboard/src/ieeesa-npm-dashboard.ts"],"sourcesContent":["/* eslint-disable no-unused-vars */\r\nexport enum DashboardSectionState {\r\n LOADING = 'LOADING',\r\n LOADED = 'LOADED',\r\n EMPTY = 'EMPTY',\r\n ERROR = 'ERROR',\r\n}\r\n","/* eslint-disable no-unused-vars */\r\nexport enum AttendanceState {\r\n CURRENTLY_ATTENDING = 'CURRENTLY_ATTENDING',\r\n NOT_ATTENDING = 'NOT_ATTENDING',\r\n}\r\n","import { MeetingRow } from './meeting-row.model';\r\n\r\n/* eslint-disable no-unused-vars */\r\n/**\r\n * Discriminates how a row in the \"Upcoming Meetings & Events\" list is rendered.\r\n * EVENT rows render as an expandable event block that owns child meetings;\r\n * STANDALONE_MEETING rows render as a single meeting card and always sort LAST\r\n * within the list.\r\n */\r\nexport enum UpcomingItemKind {\r\n EVENT = 'EVENT',\r\n STANDALONE_MEETING = 'STANDALONE_MEETING',\r\n}\r\n/* eslint-enable no-unused-vars */\r\n\r\n/**\r\n * View model for a single entry in the \"Upcoming Meetings & Events\" section.\r\n *\r\n * When {@link kind} is `EVENT` the entry renders as the expandable event block\r\n * (header badge, title, \"Day X of Y\", meeting-count sub-line, dates/timezone,\r\n * View button, and the show/hide child-meeting list). When `kind` is\r\n * `STANDALONE_MEETING` the entry renders as a single standalone meeting card\r\n * (rendered after all events).\r\n *\r\n * `startEpochMs` / `endEpochMs` carry the raw epoch-milliseconds values from the\r\n * backend and are formatted with luxon `DateTime.fromMillis`. The legacy ISO\r\n * `startDate` / `endDate` fields are retained for existing fixtures/tests.\r\n */\r\nexport interface UpcomingEvent {\r\n eventId: string;\r\n /** EVENT vs. STANDALONE_MEETING render discriminator. */\r\n kind: UpcomingItemKind;\r\n title: string;\r\n status: string;\r\n dayIndicator?: string;\r\n meetingCount: number;\r\n openForAttendanceCount: number;\r\n /** Start date-time as an ISO-8601 string (or epoch ms for fixtures). */\r\n startDateTime?: string | number;\r\n /** End date-time as an ISO-8601 string (or epoch ms for fixtures). */\r\n endDateTime?: string | number;\r\n /** Legacy ISO start date, retained for fixtures/tests. */\r\n startDate?: string;\r\n /** Legacy ISO end date, retained for fixtures/tests. */\r\n endDate?: string;\r\n timezone: string;\r\n /** Owning group label, shown on standalone-meeting cards. */\r\n groupOrCommittee?: string;\r\n /** Room / location, shown on standalone-meeting cards. */\r\n roomOrLocation?: string;\r\n /** True when the user is a member of the owning group. */\r\n isMemberOfGroup?: boolean;\r\n /** The event's child meetings (empty / lazily loaded for EVENT rows). */\r\n meetings: MeetingRow[];\r\n}\r\n","/**\r\n * Luxon format tokens used across the dashboard library for rendering\r\n * event/meeting dates, times, and timezones.\r\n *\r\n * These tokens follow the luxon `DateTime.toFormat()` convention\r\n * (NOT moment). New code in this library must use luxon exclusively.\r\n *\r\n * @see https://moment.github.io/luxon/#/formatting?id=table-of-tokens\r\n */\r\nexport const DateFormats = {\r\n /** ISO date used for request payloads, e.g. 2025-03-14. */\r\n requestPayloadFormat: 'yyyy-MM-dd',\r\n /** ISO date-time used for request payloads, e.g. 2025-03-14T09:30:00. */\r\n requestPayloadDateTimeFormat: \"yyyy-MM-dd'T'HH:mm:ss\",\r\n /** Human-readable date for display, e.g. 14 Mar 2025. */\r\n displayFormat: 'dd MMM yyyy',\r\n /** Human-readable long date for display, e.g. 14 March 2025. */\r\n displayLongFormat: 'dd MMMM yyyy',\r\n /** 24-hour time for display, e.g. 09:30. */\r\n timeFormat: 'HH:mm',\r\n /** 12-hour time with meridiem for display, e.g. 9:30 AM. */\r\n timeMeridiemFormat: 'h:mm a',\r\n /** Short timezone abbreviation for display, e.g. EST. */\r\n timezoneFormat: 'ZZZZ',\r\n /** Long timezone name for display, e.g. Eastern Standard Time. */\r\n timezoneLongFormat: 'ZZZZZ',\r\n};\r\n","/**\r\n * Pure helpers for the per-meeting attendance action state machine. No Angular /\r\n * service dependencies so they are trivially testable (property-tested as\r\n * Property 1) and reusable by `MeetingAttendanceRowComponent`.\r\n *\r\n * The handler is the single source of truth for what a meeting row's action\r\n * button should emit when activated. The displayed `AttendanceState` only\r\n * advances on a successful resolution (handled by the service reducers), so this\r\n * function is a pure mapping from the current inputs to the action to emit.\r\n */\r\nimport { AttendanceState } from '../models/attendance-state.model';\r\n\r\n/* eslint-disable no-unused-vars */\r\n/**\r\n * The action a meeting row's action button should emit when activated.\r\n * `NONE` means the activation is non-actionable (empty id or in-flight) and the\r\n * row must emit no `logAttendance` / `leaveMeeting` / navigation event.\r\n */\r\nexport enum AttendanceAction {\r\n LOG_ATTENDANCE = 'LOG_ATTENDANCE',\r\n LEAVE_MEETING = 'LEAVE_MEETING',\r\n NONE = 'NONE',\r\n}\r\n/* eslint-enable no-unused-vars */\r\n\r\n/**\r\n * Resolves the attendance action to emit for a meeting row, following the\r\n * attendance action state machine (see design: Attendance Action State Machine).\r\n *\r\n * Behavior:\r\n * - Returns `NONE` when `meetingId` is empty or undefined (non-actionable row).\r\n * - Returns `NONE` while the row is in-flight (re-entrancy guard — no further\r\n * event is emitted until the current action resolves).\r\n * - Returns `LEAVE_MEETING` when the state is `CURRENTLY_ATTENDING`.\r\n * - Returns `LOG_ATTENDANCE` when the state is `NOT_ATTENDING` or undefined.\r\n *\r\n * @param {AttendanceState | undefined} attendanceState The row's current attendance state.\r\n * @param {boolean} isInFlight Whether an attendance action for this row is awaiting resolution.\r\n * @param {string | undefined} meetingId The row's meeting identifier.\r\n * @return {AttendanceAction} The action to emit, or `NONE` when non-actionable.\r\n */\r\nexport function resolveAttendanceAction(\r\n attendanceState: AttendanceState | undefined,\r\n isInFlight: boolean,\r\n meetingId: string | undefined\r\n): AttendanceAction {\r\n if (!meetingId) {\r\n return AttendanceAction.NONE;\r\n }\r\n\r\n if (isInFlight) {\r\n return AttendanceAction.NONE;\r\n }\r\n\r\n if (attendanceState === AttendanceState.CURRENTLY_ATTENDING) {\r\n return AttendanceAction.LEAVE_MEETING;\r\n }\r\n\r\n return AttendanceAction.LOG_ATTENDANCE;\r\n}\r\n","/**\r\n * Pure luxon date/time formatting helpers for the dashboard library.\r\n *\r\n * The real \"events & meetings\" backend returns date-times as ISO-8601 strings\r\n * (e.g. \"2026-01-01T00:00:00\") together with a display timezone string\r\n * (e.g. \"(UTC-04:00) America/New_York\"). These helpers parse the ISO value and\r\n * render it in the item's own zone (never moment). A numeric epoch-milliseconds\r\n * value is also accepted for backward compatibility with fixtures/tests. All\r\n * helpers fall back gracefully to an empty string when the value is missing or\r\n * unparseable.\r\n */\r\nimport { DateTime } from 'luxon';\r\n\r\n/**\r\n * Extracts a luxon-usable IANA zone from a backend timezone string such as\r\n * \"(UTC-04:00) America/New_York\" or \"America/New_York\". Returns `undefined`\r\n * when no usable zone can be derived so luxon falls back to the local zone.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string | undefined} The IANA zone id, or undefined.\r\n */\r\nexport function extractIanaZone(\r\n timezone: string | undefined\r\n): string | undefined {\r\n if (!timezone) {\r\n return undefined;\r\n }\r\n // Strip a leading \"(UTC±HH:MM) \" offset prefix when present.\r\n const closingParen = timezone.indexOf(') ');\r\n const zone =\r\n closingParen > -1\r\n ? timezone.slice(closingParen + 2).trim()\r\n : timezone.trim();\r\n return zone.length > 0 ? zone : undefined;\r\n}\r\n\r\n/**\r\n * Parses a backend date-time value — either an ISO-8601 string\r\n * (e.g. \"2026-01-01T00:00:00\") or an epoch-milliseconds number — into a luxon\r\n * {@link DateTime} in the supplied timezone. The ISO value is treated as a wall\r\n * time in the item's zone so the rendered time matches the backend's intent.\r\n * Returns an invalid DateTime when the value is missing/unparseable.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {DateTime} The parsed luxon DateTime (may be invalid).\r\n */\r\nexport function parseBackendDateTime(\r\n value: string | number | undefined | null,\r\n timezone?: string\r\n): DateTime {\r\n const zone = extractIanaZone(timezone);\r\n if (value === undefined || value === null || value === '') {\r\n return DateTime.invalid('empty');\r\n }\r\n if (typeof value === 'number') {\r\n return zone\r\n ? DateTime.fromMillis(value, { zone })\r\n : DateTime.fromMillis(value);\r\n }\r\n // ISO string: parse as a wall time in the item's zone when known.\r\n const isoOptions = zone ? { zone } : {};\r\n const parsed = DateTime.fromISO(value, isoOptions);\r\n return parsed.isValid ? parsed : DateTime.fromISO(value);\r\n}\r\n\r\n/**\r\n * Formats a backend date-time value (ISO string or epoch ms) with luxon using\r\n * the supplied format token, honouring the supplied timezone. Returns an empty\r\n * string when the value is missing or invalid.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string} format - The luxon `toFormat` token.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The formatted value, or an empty string.\r\n */\r\nexport function formatBackendDateTime(\r\n value: string | number | undefined | null,\r\n format: string,\r\n timezone?: string\r\n): string {\r\n const parsed = parseBackendDateTime(value, timezone);\r\n return parsed.isValid ? parsed.toFormat(format) : '';\r\n}\r\n\r\n/**\r\n * Backward-compatible alias kept for existing callers. Accepts ISO strings or\r\n * epoch ms and formats them in the item's zone.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string} format - The luxon `toFormat` token.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The formatted value, or an empty string.\r\n */\r\nexport function formatEpoch(\r\n value: string | number | undefined | null,\r\n format: string,\r\n timezone?: string\r\n): string {\r\n return formatBackendDateTime(value, format, timezone);\r\n}\r\n\r\n/**\r\n * Computes a human \"Day X of Y\" indicator for a multi-day event from its start\r\n * and end date-times, relative to \"now\". Returns an empty string when the dates\r\n * are missing/invalid or the event spans a single day.\r\n * @param {string | number | undefined | null} start - Event start (ISO or epoch ms).\r\n * @param {string | number | undefined | null} end - Event end (ISO or epoch ms).\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The \"Day X of Y\" label, or an empty string.\r\n */\r\nexport function computeDayIndicator(\r\n start: string | number | undefined | null,\r\n end: string | number | undefined | null,\r\n timezone?: string\r\n): string {\r\n const zone = extractIanaZone(timezone);\r\n const startDt = parseBackendDateTime(start, timezone);\r\n const endDt = parseBackendDateTime(end, timezone);\r\n if (!startDt.isValid || !endDt.isValid) {\r\n return '';\r\n }\r\n const startDay = startDt.startOf('day');\r\n const endDay = endDt.startOf('day');\r\n const totalDays = Math.floor(endDay.diff(startDay, 'days').days) + 1;\r\n // Only meaningful for short, multi-day events (a conference-week style span).\r\n // Very long spans (e.g. a year-long series) are not shown as \"Day X of Y\".\r\n const MAX_DAY_INDICATOR_SPAN = 31;\r\n if (totalDays <= 1 || totalDays > MAX_DAY_INDICATOR_SPAN) {\r\n return '';\r\n }\r\n const now = (zone ? DateTime.now().setZone(zone) : DateTime.now()).startOf(\r\n 'day'\r\n );\r\n const clampedNow = now < startDay ? startDay : now > endDay ? endDay : now;\r\n const currentDay = Math.floor(clampedNow.diff(startDay, 'days').days) + 1;\r\n return `Day ${currentDay} of ${totalDays}`;\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { MeetingRow } from '../../models/meeting-row.model';\r\nimport { DateFormats } from '../../assets/date-formats';\r\nimport {\r\n AttendanceAction,\r\n resolveAttendanceAction,\r\n} from '../../utils/attendance-action.util';\r\nimport { formatEpoch } from '../../utils/date-format.util';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Meeting_Attendance_Row renders a single meeting within an event-group card:\r\n * the meeting-name link, group/committee, room/location, date, and\r\n * time+timezone (all luxon-formatted), together with the attendance action\r\n * button that drives the per-meeting attendance state machine.\r\n *\r\n * The component is purely presentational — it emits navigation and attendance\r\n * intents via `@Output()` and never performs navigation or HTTP itself. The\r\n * action button delegates to the pure `resolveAttendanceAction` handler so the\r\n * emit/guard logic is shared with the property-tested core (Property 1), and the\r\n * displayed state only advances when the host updates `attendanceState`.\r\n * @export\r\n * @class MeetingAttendanceRowComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-meeting-attendance-row',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './meeting-attendance-row.component.html',\r\n styleUrls: ['./meeting-attendance-row.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class MeetingAttendanceRowComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** The meeting rendered by this row. */\r\n @Input() meeting!: MeetingRow;\r\n\r\n /** The current attendance state controlling label/indicator and action. */\r\n @Input() attendanceState: AttendanceState = AttendanceState.NOT_ATTENDING;\r\n\r\n /** Whether an attendance action for this meeting is awaiting resolution. */\r\n @Input() isInFlight = false;\r\n\r\n /** Host permissions gating the log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /**\r\n * Renders the leaner \"standalone meeting\" variant used by standalone-meeting\r\n * cards (the group/location and status live on the parent card, so the row\r\n * only shows the TIME & TIMEZONE block and the attendance + View actions).\r\n */\r\n @Input() compact = false;\r\n\r\n /** Emits the meeting id when the meeting-name link is activated (Req 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the meeting id to request logging attendance (Req 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Emits the meeting id to request leaving the meeting (Req 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /** Expose the enum to the template for state comparisons. */\r\n readonly AttendanceState = AttendanceState;\r\n\r\n /**\r\n * Whether this row is actionable — a non-empty `meetingId` is required for the\r\n * meeting-name link and action button to emit anything (Req 7.10).\r\n * @return {boolean} True when the row has a usable meeting id.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isActionable(): boolean {\r\n return !!this.meeting?.meetingId;\r\n }\r\n\r\n /**\r\n * Whether the row is in the currently-attending state, which shows the\r\n * currently-attending indicator and the leave-meeting action (Req 7.5).\r\n * @return {boolean} True when the attendance state is `CURRENTLY_ATTENDING`.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isCurrentlyAttending(): boolean {\r\n return this.attendanceState === AttendanceState.CURRENTLY_ATTENDING;\r\n }\r\n\r\n /**\r\n * Whether the log-attendance button should be shown: only when the row is in\r\n * the log state (not currently attending) and the host grants\r\n * `canLogAttendance` (Req 7.6, 12.1).\r\n * @return {boolean} True when the log-attendance button is visible.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get showLogAttendanceButton(): boolean {\r\n return !this.isCurrentlyAttending && !!this.permissions?.canLogAttendance;\r\n }\r\n\r\n /**\r\n * Whether the leave-meeting button should be shown: only when the row is in\r\n * the currently-attending state and the host grants `canLeaveMeeting`\r\n * (Req 7.5, 12.2).\r\n * @return {boolean} True when the leave-meeting button is visible.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get showLeaveMeetingButton(): boolean {\r\n return this.isCurrentlyAttending && !!this.permissions?.canLeaveMeeting;\r\n }\r\n\r\n /**\r\n * Resolves a group-or-committee / room-or-location field value, substituting\r\n * the empty-field placeholder from `constants.json` when the value is empty or\r\n * undefined (Req 7.2).\r\n * @param {string | undefined} value - The raw field value from the meeting.\r\n * @return {string} The value to display, or the empty-field placeholder.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n resolveFieldValue(value: string | undefined): string {\r\n const placeholder =\r\n this.constants?.meetingRow?.emptyFieldPlaceholder ?? '—';\r\n return value && value.trim().length > 0 ? value : placeholder;\r\n }\r\n\r\n /**\r\n * Formats the meeting date for display using the shared luxon display format\r\n * (Req 7.3). Falls back to the raw value when it cannot be parsed.\r\n * @return {string} The formatted meeting date.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get formattedDate(): string {\r\n const value =\r\n this.meeting?.startDateTime ?? this.meeting?.meetingDate;\r\n return formatEpoch(\r\n value,\r\n DateFormats.displayFormat,\r\n this.meeting?.timezone\r\n );\r\n }\r\n\r\n /**\r\n * Formats the meeting time + timezone for display using luxon (Req 7.3).\r\n * The timezone abbreviation from the meeting model is appended to the parsed\r\n * time. Falls back to the raw value when it cannot be parsed.\r\n * @return {string} The formatted meeting time with timezone.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get formattedTime(): string {\r\n const timezone = this.meeting?.timezone ?? '';\r\n const startValue =\r\n this.meeting?.startDateTime ?? this.meeting?.meetingTime;\r\n const start = formatEpoch(\r\n startValue,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const end = formatEpoch(\r\n this.meeting?.endDateTime,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const range = end ? `${start} – ${end}` : start;\r\n if (!range) {\r\n return '';\r\n }\r\n return timezone ? `${range} ${timezone}` : range;\r\n }\r\n\r\n /**\r\n * Handles activation of the attendance action button. Delegates to the pure\r\n * `resolveAttendanceAction` handler and emits exactly one event based on the\r\n * resolved action: `logAttendance` for `LOG_ATTENDANCE`, `leaveMeeting` for\r\n * `LEAVE_MEETING`, and nothing for `NONE` (empty id or in-flight)\r\n * (Req 7.7, 7.8, 7.9, 7.10, 13.6).\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n onAttendanceAction(): void {\r\n const action = resolveAttendanceAction(\r\n this.attendanceState,\r\n this.isInFlight,\r\n this.meeting?.meetingId\r\n );\r\n\r\n if (action === AttendanceAction.LOG_ATTENDANCE) {\r\n this.logAttendance.emit(this.meeting.meetingId);\r\n return;\r\n }\r\n\r\n if (action === AttendanceAction.LEAVE_MEETING) {\r\n this.leaveMeeting.emit(this.meeting.meetingId);\r\n }\r\n }\r\n\r\n /**\r\n * Handles activation of the meeting-name link. Emits the meeting id only when\r\n * the row is actionable (non-empty meeting id) (Req 7.4, 7.10).\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n onOpenMeeting(): void {\r\n if (!this.isActionable) {\r\n return;\r\n }\r\n this.openMeeting.emit(this.meeting.meetingId);\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport {\r\n MatPaginatorModule,\r\n PageEvent,\r\n} from '@angular/material/paginator';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { MeetingRow } from '../../models/meeting-row.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../../models/upcoming-event.model';\r\nimport { DateFormats } from '../../assets/date-formats';\r\nimport { MeetingAttendanceRowComponent } from '../meeting-attendance-row/meeting-attendance-row.component';\r\nimport { formatEpoch } from '../../utils/date-format.util';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Event_Group_Card renders a single upcoming event as a card: the status badge,\r\n * title, day indicator, meeting-count summary sub-line, start/end date, and\r\n * timezone (all luxon-formatted). It exposes a \"View Event\" action, a\r\n * show/hide toggle for the meeting list labeled with the open-for-attendance\r\n * count, the per-event meeting rows (one {@link MeetingAttendanceRowComponent}\r\n * per meeting on the current page), and a per-card paginator.\r\n *\r\n * The component is purely presentational — it emits navigation, attendance, and\r\n * pagination intents via `@Output()` and never performs navigation or HTTP\r\n * itself. Meeting-row outputs (`openMeeting`/`logAttendance`/`leaveMeeting`) are\r\n * bubbled upward unchanged so the container can delegate to the service.\r\n * @export\r\n * @class EventGroupCardComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-event-group-card',\r\n standalone: true,\r\n imports: [CommonModule, MatPaginatorModule, MeetingAttendanceRowComponent],\r\n templateUrl: './event-group-card.component.html',\r\n styleUrls: ['./event-group-card.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class EventGroupCardComponent {\r\n /** User-facing strings sourced from `constants.json`. */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** Enum reference for EVENT vs STANDALONE_MEETING comparisons in the template. */\r\n readonly itemKinds = UpcomingItemKind;\r\n\r\n /**\r\n * The event status slugified into a BEM modifier suffix (lowercase, spaces to\r\n * hyphens), e.g. \"In Progress\" -> \"in-progress\", used to colour the status\r\n * pill per status.\r\n * @return {string} The status modifier suffix.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get statusModifier(): string {\r\n return (this.event?.status ?? '')\r\n .trim()\r\n .toLowerCase()\r\n .replace(/\\s+/g, '-');\r\n }\r\n\r\n /** The upcoming event rendered by this card. */\r\n @Input() event!: UpcomingEvent;\r\n\r\n /** Host permissions gating the per-row log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Map of meeting id to current attendance state, passed down to each row. */\r\n @Input() attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** Set of meeting ids with an attendance action awaiting resolution. */\r\n @Input() inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** Whether the host has determined the viewport is at/below the mobile breakpoint. */\r\n @Input() isMobileView = false;\r\n\r\n /** Emits the event id when the \"View Event\" button is activated (Req 6.4). */\r\n @Output() viewEvent = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row's meeting-name link is activated (Req 6.7, 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row requests logging attendance (Req 6.7, 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row requests leaving the meeting (Req 6.7, 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the requested page when the per-card paginator changes (Req 6.9, 3.3). */\r\n @Output() pageChange = new EventEmitter<PageChange>();\r\n\r\n /**\r\n * Emits the one-based page to load when the meeting list is opened (or paged)\r\n * so the container can lazily fetch the event's child meetings from the\r\n * backend. Standalone-meeting cards never emit this.\r\n */\r\n @Output() loadMeetings = new EventEmitter<number>();\r\n\r\n /** The default page size for the per-card meeting paginator. */\r\n readonly defaultPageSize = 5;\r\n\r\n /** The current zero-based page index of the meeting list. */\r\n pageIndex = 0;\r\n\r\n /** The current page size of the meeting list. */\r\n pageSize = this.defaultPageSize;\r\n\r\n /** Whether the meeting list is currently shown (toggled open). */\r\n isMeetingListOpen = false;\r\n\r\n /**\r\n * Whether this card renders a STANDALONE_MEETING (leaner single-meeting card\r\n * with no child-meeting list) rather than an expandable EVENT block.\r\n * @return {boolean} True for standalone-meeting cards.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandalone(): boolean {\r\n return this.event?.kind === UpcomingItemKind.STANDALONE_MEETING;\r\n }\r\n\r\n /**\r\n * The full list of meetings for the event, defaulting to an empty list when\r\n * the event has none.\r\n * @return {MeetingRow[]} The event's meetings.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetings(): MeetingRow[] {\r\n return this.event?.meetings ?? [];\r\n }\r\n\r\n /**\r\n * The total number of meetings for the event (paginator length). Uses the\r\n * backend `meetingCount` (the full total) rather than the length of the\r\n * currently loaded page, so the paginator can advance through every page.\r\n * @return {number} The total meeting count.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get totalMeetings(): number {\r\n return this.event?.meetingCount || this.meetings.length;\r\n }\r\n\r\n /**\r\n * The meetings to render for the current page. The server returns exactly one\r\n * page of meetings into `event.meetings`, so the card renders them as-is\r\n * without local slicing (pagination is server-side).\r\n * @return {MeetingRow[]} The meetings on the current page.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get pagedMeetings(): MeetingRow[] {\r\n return this.meetings;\r\n }\r\n\r\n /**\r\n * The one-based index of the first meeting shown on the current page, or 0\r\n * when there are no meetings.\r\n * @return {number} The start index for the range template.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeStart(): number {\r\n return this.totalMeetings === 0 ? 0 : this.pageIndex * this.pageSize + 1;\r\n }\r\n\r\n /**\r\n * The one-based index of the last meeting shown on the current page, clamped\r\n * to the total meeting count.\r\n * @return {number} The end index for the range template.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeEnd(): number {\r\n return Math.min((this.pageIndex + 1) * this.pageSize, this.totalMeetings);\r\n }\r\n\r\n /**\r\n * The paginator range label (e.g. \"Showing 1-5 of 12\") built from the\r\n * `constants.json` range template with the current start/end/total values.\r\n * @return {string} The formatted range label.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeLabel(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.paginator?.rangeTemplate ??\r\n 'Showing {start}-{end} of {total}';\r\n return template\r\n .replace('{start}', `${this.rangeStart}`)\r\n .replace('{end}', `${this.rangeEnd}`)\r\n .replace('{total}', `${this.totalMeetings}`);\r\n }\r\n\r\n /**\r\n * The meeting-count summary sub-line (e.g. \"12 meetings\") built from the\r\n * `constants.json` total template with the event's meeting count.\r\n * @return {string} The formatted meeting-count summary.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetingCountSummary(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.paginator?.totalTemplate ??\r\n '{total} meetings';\r\n return template.replace('{total}', `${this.event?.meetingCount ?? 0}`);\r\n }\r\n\r\n /**\r\n * The header sub-line: the group · location line for a STANDALONE meeting, or\r\n * the \"{n} meetings scheduled across the event\" summary for an EVENT when its\r\n * meeting count is known (hidden until the count is loaded so it never shows\r\n * \"0 meetings\").\r\n * @return {string} The sub-line text, or an empty string to hide it.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get subtitleText(): string {\r\n if (this.isStandalone) {\r\n const group = this.event?.groupOrCommittee ?? '';\r\n const location = this.event?.roomOrLocation ?? '';\r\n if (group && location) {\r\n return `${group} \\u00b7 ${location}`;\r\n }\r\n return group || location;\r\n }\r\n return (this.event?.meetingCount ?? 0) > 0 ? this.meetingCountSummary : '';\r\n }\r\n\r\n /**\r\n * The meeting-list show/hide toggle label. When the list is hidden the label\r\n * reads \"Show Meetings ({count} open for attendance)\" built from the\r\n * `constants.json` templates and the event's open-for-attendance count; when\r\n * the list is shown the label reads the configured hide label (Req 6.5).\r\n * @return {string} The toggle button label.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetingListToggleLabel(): string {\r\n const toggle = this.constants?.eventGroupCard?.meetingListToggle;\r\n if (this.isMeetingListOpen) {\r\n return toggle?.hideLabel ?? 'Hide meetings';\r\n }\r\n return toggle?.showLabel ?? 'Show meetings';\r\n }\r\n\r\n /**\r\n * The \"{count} Meetings open for attendance\" summary shown in the event's\r\n * meetings bar, built from the `constants.json` template and the event's\r\n * open-for-attendance count (Req 6.5).\r\n * @return {string} The formatted open-for-attendance summary.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get openForAttendanceSummary(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.openForAttendanceTemplate ??\r\n '{count} Meetings open for attendance';\r\n return template.replace(\r\n '{count}',\r\n `${this.event?.openForAttendanceCount ?? 0}`\r\n );\r\n }\r\n\r\n /**\r\n * The {@link MeetingRow} view model for a STANDALONE_MEETING card, projected\r\n * from the event entry so the shared {@link MeetingAttendanceRowComponent}\r\n * renders its time/timezone block and attendance action.\r\n * @return {MeetingRow} The standalone meeting row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get standaloneMeeting(): MeetingRow {\r\n return {\r\n meetingId: this.event?.eventId ?? '',\r\n meetingName: this.event?.title ?? '',\r\n groupOrCommittee: this.event?.groupOrCommittee,\r\n roomOrLocation: this.event?.roomOrLocation,\r\n startDateTime: this.event?.startDateTime ?? this.event?.startDate,\r\n endDateTime: this.event?.endDateTime ?? this.event?.endDate,\r\n timezone: this.event?.timezone ?? '',\r\n status: this.event?.status,\r\n isMemberOfGroup: this.event?.isMemberOfGroup,\r\n };\r\n }\r\n\r\n /**\r\n * The formatted \"start – end time (timezone)\" string for a STANDALONE meeting,\r\n * mirroring the inner meeting row's TIME & TIMEZONE value.\r\n * @return {string} The formatted time + timezone.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get standaloneTime(): string {\r\n const timezone = this.event?.timezone ?? '';\r\n const start = formatEpoch(\r\n this.event?.startDateTime ?? this.event?.startDate,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const end = formatEpoch(\r\n this.event?.endDateTime ?? this.event?.endDate,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const range = end ? `${start} \\u2013 ${end}` : start;\r\n if (!range) {\r\n return '';\r\n }\r\n return timezone ? `${range} ${timezone}` : range;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting is currently being attended (drives the pill\r\n * and the leave action).\r\n * @return {boolean} True when the standalone meeting is currently attending.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandaloneAttending(): boolean {\r\n return (\r\n this.resolveAttendanceState(this.standaloneMeeting) ===\r\n AttendanceState.CURRENTLY_ATTENDING\r\n );\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting's Log Attendance button is shown (not\r\n * attending and the host grants the permission).\r\n * @return {boolean} True when the log-attendance button is visible.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get showStandaloneLog(): boolean {\r\n return !this.isStandaloneAttending && !!this.permissions?.canLogAttendance;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting's Leave Meeting button is shown (attending\r\n * and the host grants the permission).\r\n * @return {boolean} True when the leave-meeting button is visible.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get showStandaloneLeave(): boolean {\r\n return this.isStandaloneAttending && !!this.permissions?.canLeaveMeeting;\r\n }\r\n\r\n /** The luxon-formatted start date of the event (ISO or epoch ms) (Req 6.2). */\r\n get formattedStartDate(): string {\r\n return this.formatDate(\r\n this.event?.startDateTime ?? this.event?.startDate\r\n );\r\n }\r\n\r\n /** The luxon-formatted end date of the event (ISO or epoch ms) (Req 6.2). */\r\n get formattedEndDate(): string {\r\n return this.formatDate(this.event?.endDateTime ?? this.event?.endDate);\r\n }\r\n\r\n /**\r\n * `trackBy` for the meeting-row `*ngFor`, keyed by the stable meeting id so\r\n * Angular reuses row components across pagination/state changes (Req 6.7, 14.4).\r\n * @param {number} _index - The iteration index (unused).\r\n * @param {MeetingRow} meeting - The meeting for this row.\r\n * @return {string} The stable track key (meeting id).\r\n * @memberof EventGroupCardComponent\r\n */\r\n trackByMeetingId(_index: number, meeting: MeetingRow): string {\r\n return meeting?.meetingId ?? `${_index}`;\r\n }\r\n\r\n /**\r\n * Resolves the attendance state for a meeting from the `attendanceStates` map,\r\n * defaulting to `NOT_ATTENDING` when the map has no entry for it.\r\n * @param {MeetingRow} meeting - The meeting to resolve state for.\r\n * @return {AttendanceState} The attendance state passed to the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n resolveAttendanceState(meeting: MeetingRow): AttendanceState {\r\n return (\r\n this.attendanceStates?.[meeting?.meetingId] ??\r\n AttendanceState.NOT_ATTENDING\r\n );\r\n }\r\n\r\n /**\r\n * Resolves whether a meeting has an attendance action in flight from the\r\n * `inFlightMeetingIds` set.\r\n * @param {MeetingRow} meeting - The meeting to check.\r\n * @return {boolean} True when the meeting's action is awaiting resolution.\r\n * @memberof EventGroupCardComponent\r\n */\r\n resolveIsInFlight(meeting: MeetingRow): boolean {\r\n return this.inFlightMeetingIds?.has(meeting?.meetingId) ?? false;\r\n }\r\n\r\n /**\r\n * Toggles the meeting-list visibility, lazily requesting the first page of the\r\n * event's child meetings from the container the first time it is opened (Req 6.6).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onToggleMeetingList(): void {\r\n this.isMeetingListOpen = !this.isMeetingListOpen;\r\n if (this.isMeetingListOpen) {\r\n this.loadMeetings.emit(this.pageIndex + 1);\r\n }\r\n }\r\n\r\n /**\r\n * Handles the \"View Event\" button, emitting the event id to the host (Req 6.4).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onViewEvent(): void {\r\n this.viewEvent.emit(this.event?.eventId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's meeting-name link activation upward (Req 6.7, 7.4).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.openMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's log-attendance request upward (Req 6.7, 7.7).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.logAttendance.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's leave-meeting request upward (Req 6.7, 7.8).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.leaveMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Handles the per-card paginator change, updating the local page state and\r\n * emitting the requested page as a {@link PageChange} (Req 6.9, 3.3).\r\n * @param {PageEvent} event - The Material paginator page event.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onPageChange(event: PageEvent): void {\r\n this.pageIndex = event.pageIndex;\r\n this.pageSize = event.pageSize;\r\n this.pageChange.emit({\r\n pageIndex: event.pageIndex,\r\n pageSize: event.pageSize,\r\n });\r\n // Request the newly selected page's child meetings from the container.\r\n this.loadMeetings.emit(event.pageIndex + 1);\r\n }\r\n\r\n /**\r\n * Formats a date for display, preferring the epoch-milliseconds value (from\r\n * the real API) formatted in the event's timezone and falling back to a legacy\r\n * ISO string. Returns an empty string when neither is present.\r\n * @param {number | undefined} epochMs - The epoch-milliseconds value.\r\n * @param {string | undefined} isoValue - The legacy ISO fallback.\r\n * @return {string} The formatted date or an empty string.\r\n * @memberof EventGroupCardComponent\r\n */\r\n private formatDate(value: string | number | undefined | null): string {\r\n return formatEpoch(value, DateFormats.displayFormat, this.event?.timezone);\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport {\r\n MatPaginatorModule,\r\n PageEvent,\r\n} from '@angular/material/paginator';\r\nimport { LoaderComponent } from '@ieeesa-npm/presentation';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { DashboardSectionState } from '../../models/dashboard-section-state.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport { UpcomingEvent } from '../../models/upcoming-event.model';\r\nimport { EventGroupCardComponent } from '../event-group-card/event-group-card.component';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Upcoming_Meetings_Events renders the \"Upcoming Meetings & Events\" dashboard\r\n * section: a section title and \"View All\" link, a collapse/expand toggle that\r\n * starts expanded, and one {@link EventGroupCardComponent} per upcoming event.\r\n *\r\n * The section is driven by its `sectionState` input: it shows the Loader while\r\n * `LOADING`, the event-group cards while `LOADED`, the empty-state message while\r\n * `EMPTY`, and the error message while `ERROR` — the four regions are mutually\r\n * exclusive (Req 13.1, 13.2, 13.3, 13.5). The component is purely\r\n * presentational: \"View All\" emits `viewAll` (Req 5.1, 5.2), the collapse toggle\r\n * flips `isExpanded` and the card-list visibility while exposing\r\n * `[attr.aria-expanded]` (Req 5.3, 5.4, 14.3), and each card is rendered via\r\n * `*ngFor` with {@link trackByEventId} to preserve input order (Req 5.5, 5.6,\r\n * 14.4). Card outputs (`viewEvent`/`openMeeting`/`logAttendance`/`leaveMeeting`)\r\n * are bubbled upward unchanged, and each card's `pageChange` is mapped to\r\n * `meetingPageChange` tagged with the originating event id (Req 6.9).\r\n * @export\r\n * @class UpcomingMeetingsEventsComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-upcoming-meetings-events',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatPaginatorModule,\r\n LoaderComponent,\r\n EventGroupCardComponent,\r\n ],\r\n templateUrl: './upcoming-meetings-events.component.html',\r\n styleUrls: ['./upcoming-meetings-events.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class UpcomingMeetingsEventsComponent {\r\n /** User-facing strings sourced from `constants.json`. */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** Enum reference for template comparisons against `sectionState`. */\r\n readonly sectionStates = DashboardSectionState;\r\n\r\n /** The upcoming events rendered as event-group cards (Req 5.5, 5.6). */\r\n @Input() events: UpcomingEvent[] = [];\r\n\r\n /** The load/empty/error status driving the section's mutually exclusive regions. */\r\n @Input() sectionState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** Host permissions gating the per-row log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Map of meeting id to current attendance state, passed down to each card. */\r\n @Input() attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** Set of meeting ids with an attendance action awaiting resolution. */\r\n @Input() inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** Whether the host has determined the viewport is at/below the mobile breakpoint. */\r\n @Input() isMobileView = false;\r\n\r\n /** Emits when the \"View All\" link is activated (Req 5.2). */\r\n @Output() viewAll = new EventEmitter<void>();\r\n\r\n /** Bubbles the event id when a card's \"View Event\" button is activated (Req 6.4). */\r\n @Output() viewEvent = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card's meeting-name link is activated (Req 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card requests logging attendance (Req 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card requests leaving the meeting (Req 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the requested page tagged with its event id when a card paginates (Req 6.9). */\r\n @Output() meetingPageChange = new EventEmitter<{ eventId: string } & PageChange>();\r\n\r\n /** Emits the event id + one-based page to lazily load an event's child meetings. */\r\n @Output() loadEventMeetings = new EventEmitter<{ eventId: string; page: number }>();\r\n\r\n /** Whether the section's card list is currently expanded; starts collapsed. */\r\n isExpanded = false;\r\n\r\n /** Section-level page size — 5 events/meetings per page per the design. */\r\n readonly sectionPageSize = 5;\r\n\r\n /** The current zero-based page index of the section list. */\r\n sectionPageIndex = 0;\r\n\r\n /** The total number of events/meetings in the section (paginator length). */\r\n get totalItems(): number {\r\n return this.events?.length ?? 0;\r\n }\r\n\r\n /**\r\n * The slice of events/meetings for the current section page (5 per page),\r\n * used by the card `*ngFor`.\r\n * @return {UpcomingEvent[]} The events on the current page.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get pagedEvents(): UpcomingEvent[] {\r\n const start = this.sectionPageIndex * this.sectionPageSize;\r\n return (this.events ?? []).slice(start, start + this.sectionPageSize);\r\n }\r\n\r\n /** The one-based index of the first item shown on the current page. */\r\n get sectionRangeStart(): number {\r\n return this.totalItems === 0\r\n ? 0\r\n : this.sectionPageIndex * this.sectionPageSize + 1;\r\n }\r\n\r\n /** The one-based index of the last item shown on the current page. */\r\n get sectionRangeEnd(): number {\r\n return Math.min(\r\n (this.sectionPageIndex + 1) * this.sectionPageSize,\r\n this.totalItems\r\n );\r\n }\r\n\r\n /**\r\n * The section paginator range label (e.g. \"1-5 of 20 Meetings & Events\")\r\n * built from the `constants.json` template.\r\n * @return {string} The formatted range label.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get sectionRangeLabel(): string {\r\n const template =\r\n this.constants?.upcomingSection?.paginator?.rangeTemplate ??\r\n '{start}-{end} of {total} Meetings & Events';\r\n return template\r\n .replace('{start}', `${this.sectionRangeStart}`)\r\n .replace('{end}', `${this.sectionRangeEnd}`)\r\n .replace('{total}', `${this.totalItems}`);\r\n }\r\n\r\n /**\r\n * Handles the section paginator change, updating the current section page.\r\n * @param {PageEvent} event - The Material paginator page event.\r\n * @return {void}\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onSectionPageChange(event: PageEvent): void {\r\n this.sectionPageIndex = event.pageIndex;\r\n }\r\n\r\n /**\r\n * Allows the host/container to open or close the section (e.g. a \"Jump to\"\r\n * shortcut opens it). Writing the input mirrors the value onto the internal\r\n * expand state while leaving the user's own toggle free to change it after.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n @Input()\r\n set expanded(value: boolean) {\r\n this.isExpanded = !!value;\r\n }\r\n get expanded(): boolean {\r\n return this.isExpanded;\r\n }\r\n\r\n /**\r\n * Emits the new expanded state whenever the user toggles the section, so a\r\n * two-way `[(expanded)]` binding keeps the host's flag in sync (otherwise a\r\n * host-opened section the user then collapses leaves the host flag stale,\r\n * making a repeat \"Jump to\" a no-op).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n @Output() expandedChange = new EventEmitter<boolean>();\r\n\r\n /**\r\n * `trackBy` for the event-group-card `*ngFor`, keyed by the stable event id so\r\n * Angular renders exactly one card per event in input order (Req 5.5, 5.6, 14.4).\r\n * @param {number} index - The iteration index (fallback key).\r\n * @param {UpcomingEvent} event - The event for this card.\r\n * @return {string} The stable track key (event id).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n trackByEventId(index: number, event: UpcomingEvent): string {\r\n return event?.eventId ?? `${index}`;\r\n }\r\n\r\n /**\r\n * Toggles the section's expanded/collapsed state, inverting the card-list\r\n * visibility and the exposed `aria-expanded` value (Req 5.4, 14.3).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onToggleExpanded(): void {\r\n this.isExpanded = !this.isExpanded;\r\n this.expandedChange.emit(this.isExpanded);\r\n }\r\n\r\n /**\r\n * Handles the \"View All\" link, emitting the `viewAll` intent to the host (Req 5.2).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onViewAll(): void {\r\n this.viewAll.emit();\r\n }\r\n\r\n /**\r\n * Bubbles a card's \"View Event\" activation upward (Req 6.4).\r\n * @param {string} eventId - The event id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onViewEvent(eventId: string): void {\r\n this.viewEvent.emit(eventId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's meeting-name link activation upward (Req 7.4).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.openMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's log-attendance request upward (Req 7.7).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.logAttendance.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's leave-meeting request upward (Req 7.8).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.leaveMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Maps a card's `pageChange` into a `meetingPageChange` tagged with the\r\n * originating event id so the host can page the correct event (Req 6.9).\r\n * @param {string} eventId - The id of the event whose card paginated.\r\n * @param {PageChange} page - The requested page from the card paginator.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onMeetingPageChange(eventId: string, page: PageChange): void {\r\n this.meetingPageChange.emit({ eventId, ...page });\r\n }\r\n\r\n /**\r\n * Bubbles a card's lazy child-meeting load request upward, tagged with the\r\n * originating event id so the container can fetch that event's meetings.\r\n * @param {string} eventId - The event whose meetings to load.\r\n * @param {number} page - The one-based page requested by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLoadEventMeetings(eventId: string, page: number): void {\r\n this.loadEventMeetings.emit({ eventId, page });\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * Identifies which dashboard section a \"Jump to\" shortcut targets, emitted via\r\n * {@link DashboardWelcomeHeaderComponent.shortcutSelected} for the host/container\r\n * to scroll to or navigate.\r\n */\r\n// eslint-disable-next-line no-unused-vars\r\nexport enum DashboardJumpTarget {\r\n // eslint-disable-next-line no-unused-vars\r\n MEETINGS = 'MEETINGS',\r\n // eslint-disable-next-line no-unused-vars\r\n GROUPS = 'GROUPS',\r\n}\r\n\r\n/**\r\n * A single \"Jump to\" shortcut rendered in the welcome header: a circular icon\r\n * that expands on hover/focus into a pill showing the section label and its\r\n * count badge.\r\n */\r\ninterface JumpShortcut {\r\n target: DashboardJumpTarget;\r\n label: string;\r\n iconUrl: string;\r\n ariaLabel: string;\r\n count: number;\r\n}\r\n\r\n/**\r\n * Welcome_Header renders the personalized greeting and the \"Jump to\" shortcut\r\n * control at the top of the dashboard.\r\n *\r\n * The greeting is composed from the greeting label in `constants.json` and the\r\n * supplied `userName`, falling back to the configured fallback greeting when the\r\n * name is empty or undefined. The \"Jump to\" control shows one circular icon per\r\n * dashboard section (Upcoming Meetings & Events, Your Groups); hovering or\r\n * focusing an icon expands it into a pill with the section label and a count\r\n * badge (the counts are supplied by the host via `meetingsCount` /\r\n * `groupsCount`). Activating a shortcut emits {@link shortcutSelected} with the\r\n * target section for the host to act on. Purely presentational — no API work.\r\n * @export\r\n * @class DashboardWelcomeHeaderComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-dashboard-welcome-header',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './dashboard-welcome-header.component.html',\r\n styleUrls: ['./dashboard-welcome-header.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class DashboardWelcomeHeaderComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private readonly constants: any = constants;\r\n /** User-facing strings sourced from `constants.json`. */\r\n readonly texts = this.constants?.welcomeHeader;\r\n\r\n /** Enum reference for template comparisons. */\r\n readonly jumpTarget = DashboardJumpTarget;\r\n\r\n private userNameValue = '';\r\n /**\r\n * The signed-in user's display name. Drives the personalized greeting; when\r\n * empty or undefined the greeting falls back to the configured fallback text.\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n @Input()\r\n set userName(value: string) {\r\n this.userNameValue = value ?? '';\r\n }\r\n get userName(): string {\r\n return this.userNameValue;\r\n }\r\n\r\n private meetingsCountValue = 0;\r\n /** Count shown in the Upcoming Meetings & Events shortcut badge. */\r\n @Input()\r\n set meetingsCount(value: number) {\r\n this.meetingsCountValue = value ?? 0;\r\n this.buildShortcuts();\r\n }\r\n get meetingsCount(): number {\r\n return this.meetingsCountValue;\r\n }\r\n\r\n private groupsCountValue = 0;\r\n /** Count shown in the Your Groups shortcut badge. */\r\n @Input()\r\n set groupsCount(value: number) {\r\n this.groupsCountValue = value ?? 0;\r\n this.buildShortcuts();\r\n }\r\n get groupsCount(): number {\r\n return this.groupsCountValue;\r\n }\r\n\r\n /** Emits the selected \"Jump to\" target for the host to act on. */\r\n @Output() shortcutSelected = new EventEmitter<DashboardJumpTarget>();\r\n\r\n /** The jump shortcuts rendered in the control, rebuilt when counts change. */\r\n shortcuts: JumpShortcut[] = this.buildShortcutList();\r\n\r\n /**\r\n * The personalized greeting: the greeting label plus the user's name when\r\n * present, otherwise the configured fallback greeting.\r\n * @readonly\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n get greeting(): string {\r\n const name = this.userName?.trim();\r\n return name\r\n ? `${this.texts?.greeting}${name}!`\r\n : `${this.texts?.fallbackGreeting}!`;\r\n }\r\n\r\n /**\r\n * Emits the chosen shortcut's target for the host to scroll/navigate to.\r\n * @param {DashboardJumpTarget} target - The selected section.\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n onShortcutClick(target: DashboardJumpTarget): void {\r\n this.shortcutSelected.emit(target);\r\n }\r\n\r\n /**\r\n * TrackBy for the shortcut list.\r\n * @param {number} _index\r\n * @param {JumpShortcut} shortcut\r\n * @return {string}\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n trackByTarget(_index: number, shortcut: JumpShortcut): string {\r\n return shortcut.target;\r\n }\r\n\r\n /** Rebuilds the shortcut list so the template reflects the latest counts. */\r\n private buildShortcuts(): void {\r\n this.shortcuts = this.buildShortcutList();\r\n }\r\n\r\n /**\r\n * Builds the shortcut view models from `constants.json` and the current\r\n * counts.\r\n * @return {JumpShortcut[]}\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n private buildShortcutList(): JumpShortcut[] {\r\n const shortcutTexts = this.constants?.welcomeHeader?.shortcuts;\r\n return [\r\n {\r\n target: DashboardJumpTarget.MEETINGS,\r\n label: shortcutTexts?.meetings?.label,\r\n iconUrl: shortcutTexts?.meetings?.iconUrl,\r\n ariaLabel: shortcutTexts?.meetings?.ariaLabel,\r\n count: this.meetingsCountValue,\r\n },\r\n {\r\n target: DashboardJumpTarget.GROUPS,\r\n label: shortcutTexts?.groups?.label,\r\n iconUrl: shortcutTexts?.groups?.iconUrl,\r\n ariaLabel: shortcutTexts?.groups?.ariaLabel,\r\n count: this.groupsCountValue,\r\n },\r\n ];\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\r\nimport {\r\n IconButton,\r\n IconButtonComponent,\r\n LoaderComponent,\r\n} from '@ieeesa-npm/presentation';\r\nimport { DashboardSectionState } from '../../models/dashboard-section-state.model';\r\nimport {\r\n GroupHierarchyNode,\r\n GroupRow,\r\n} from '../../models/group-row.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * A single rendered table row. Either a top-level group row (`kind: 'group'`,\r\n * carrying the full {@link GroupRow}) or a hierarchy node row (`kind:\r\n * 'hierarchy'`) revealed step-by-step as the user drills down. `nodeIndex` is\r\n * the node's position in the group's `hierarchy[]`, used to drive the next\r\n * drill-down level and the per-node toggle (matching the Groups module, where\r\n * each level reveals only its next child and that child carries its own +/−).\r\n */\r\ninterface TableRow {\r\n kind: 'group' | 'hierarchy';\r\n group?: GroupRow;\r\n node?: GroupHierarchyNode;\r\n /** Index of this node within the group's hierarchy[] (hierarchy rows only). */\r\n nodeIndex?: number;\r\n level: number;\r\n}\r\n\r\n/**\r\n * Groups_Section (`ieeesa-your-groups`) renders the signed-in user's groups in\r\n * a collapsible card as a custom hierarchy table styled like the My Profile\r\n * Find Groups tree: each group row carries a blue +/- toggle (when it has an\r\n * ancestor hierarchy) that expands to reveal the group's hierarchy path\r\n * (root→leaf), indented. Columns: Group, Type, Officer Role, Affiliation,\r\n * Member Level (the member level renders as a coloured pill — green for an\r\n * assigned level, amber for \"Unassigned\"). The card paginates the top-level\r\n * groups (5 per page).\r\n *\r\n * Purely presentational: data arrives via `@Input`, intents leave via\r\n * `@Output`; no API or navigation here. States (loader / empty / error / table)\r\n * are driven by `sectionState`.\r\n * @export\r\n * @class YourGroupsComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-your-groups',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatPaginatorModule,\r\n LoaderComponent,\r\n IconButtonComponent,\r\n ],\r\n templateUrl: './your-groups.component.html',\r\n styleUrls: ['./your-groups.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class YourGroupsComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private readonly constants: any = constants;\r\n /** User-facing strings sourced from `constants.json`. */\r\n readonly texts = this.constants?.groupsSection;\r\n\r\n /** Enum reference for template comparisons against `sectionState`. */\r\n readonly sectionStates = DashboardSectionState;\r\n\r\n /** Per-level indentation step (px) for the expanded hierarchy rows. */\r\n readonly indentPerLevel = 28;\r\n\r\n /** Selectable \"Items per page\" page sizes. */\r\n readonly pageSizeOptions: number[] = [5, 10, 25];\r\n\r\n /**\r\n * Expand (+) icon button — the SAME sprite icon the Groups package uses for\r\n * its tree expand toggle (icon-expand-collapse-plus), rendered via the shared\r\n * IconButtonComponent for a consistent look across the app.\r\n */\r\n readonly expandIconButton: IconButton = {\r\n id: 1,\r\n iconURL: 'assets/images/sprites/sprites.svg#icon-expand-collapse-plus',\r\n ariaLabel: 'Expand group',\r\n toolTip: 'Expand group',\r\n };\r\n\r\n /** Collapse (−) icon button — the Groups package's icon-expand-collapse-minus. */\r\n readonly collapseIconButton: IconButton = {\r\n id: 2,\r\n iconURL: 'assets/images/sprites/sprites.svg#icon-expand-collapse-minus',\r\n ariaLabel: 'Collapse group',\r\n toolTip: 'Collapse group',\r\n };\r\n\r\n /**\r\n * Returns the +/- toggle icon button for a level, matching the Groups tree:\r\n * the minus (collapse) icon when that level is expanded, otherwise the plus\r\n * (expand) icon.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @return {IconButton}\r\n * @memberof YourGroupsComponent\r\n */\r\n getToggleButton(group: GroupRow, index: number): IconButton {\r\n const button = this.isLevelExpanded(group, index)\r\n ? this.collapseIconButton\r\n : this.expandIconButton;\r\n // Include the target's name so each toggle has a distinct accessible name\r\n // (e.g. \"Expand group Tech working\"). Return a NEW object so the shared\r\n // expand/collapse configs are never mutated.\r\n const name =\r\n index < 0\r\n ? group.group\r\n : group.hierarchy?.[index]?.groupName ?? group.group;\r\n return { ...button, ariaLabel: `${button.ariaLabel} ${name}` };\r\n }\r\n\r\n private groupsValue: GroupRow[] = [];\r\n /** The groups rendered in the table. */\r\n @Input()\r\n set groups(value: GroupRow[]) {\r\n this.groupsValue = value ?? [];\r\n this.rebuildRows();\r\n }\r\n get groups(): GroupRow[] {\r\n return this.groupsValue;\r\n }\r\n\r\n /** The section's load/empty/error state driving the mutually-exclusive regions. */\r\n @Input() sectionState: DashboardSectionState = DashboardSectionState.LOADED;\r\n\r\n /** Total number of groups (for the \"{n} Groups\" count and paginator). */\r\n @Input() totalGroups = 0;\r\n\r\n private pageIndexValue = 0;\r\n /** Current zero-based page index. */\r\n @Input()\r\n set pageIndex(value: number) {\r\n this.pageIndexValue = value ?? 0;\r\n this.rebuildRows();\r\n }\r\n get pageIndex(): number {\r\n return this.pageIndexValue;\r\n }\r\n\r\n private pageSizeValue = 5;\r\n /** Current page size (defaults to 5 rows per page per the design). */\r\n @Input()\r\n set pageSize(value: number) {\r\n this.pageSizeValue = value ?? 5;\r\n this.rebuildRows();\r\n }\r\n get pageSize(): number {\r\n return this.pageSizeValue;\r\n }\r\n\r\n /** Emits when the \"View All\" link is activated. */\r\n @Output() viewAllGroups = new EventEmitter<void>();\r\n\r\n /** Emits the requested page when the paginator changes. */\r\n @Output() pageChange = new EventEmitter<PageChange>();\r\n\r\n /**\r\n * Emits the new expanded state whenever the user toggles the card, so a\r\n * two-way `[(expanded)]` binding keeps the host's flag in sync. Without this,\r\n * a host that opened the card (expanded=true) and then the user collapsing it\r\n * would leave the host flag stale, so re-opening via the same input value\r\n * would be a no-op.\r\n * @memberof YourGroupsComponent\r\n */\r\n @Output() expandedChange = new EventEmitter<boolean>();\r\n\r\n /** Whether the card is expanded (table visible). Starts collapsed. */\r\n isExpanded = false;\r\n\r\n /**\r\n * Allows the host/container to open or close the card (e.g. a \"Jump to\"\r\n * shortcut opens it).\r\n * @memberof YourGroupsComponent\r\n */\r\n @Input()\r\n set expanded(value: boolean) {\r\n this.isExpanded = !!value;\r\n }\r\n get expanded(): boolean {\r\n return this.isExpanded;\r\n }\r\n\r\n /**\r\n * Keys of the hierarchy levels currently expanded, each `\"<groupId>:<index>\"`.\r\n * Index -1 is the group row itself (its toggle reveals the first hierarchy\r\n * node); index N is the Nth hierarchy node (its toggle reveals node N+1). A\r\n * level only reveals the NEXT node, matching the Groups module's step-by-step\r\n * drill-down.\r\n */\r\n private readonly expandedKeys = new Set<string>();\r\n\r\n /** The flattened rows currently rendered (group rows + any revealed hierarchy rows). */\r\n visibleRows: TableRow[] = [];\r\n\r\n /**\r\n * The count shown in the header subtitle — the server total when provided,\r\n * otherwise the number of groups.\r\n * @readonly\r\n * @memberof YourGroupsComponent\r\n */\r\n get groupCount(): number {\r\n return this.totalGroups || this.groups.length || 0;\r\n }\r\n\r\n /**\r\n * Builds the expand/collapse key for a hierarchy level. Index -1 is the group\r\n * row itself; index N is the Nth hierarchy node.\r\n * @param {GroupRow} group\r\n * @param {number} index\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n private levelKey(group: GroupRow, index: number): string {\r\n return `${group.groupId}:${index}`;\r\n }\r\n\r\n /**\r\n * Whether a level shows a +/- toggle.\r\n *\r\n * - Group row (index -1): expandable when it has ANY hierarchy node, matching\r\n * the Groups module which shows the toggle on every group that has related\r\n * hierarchy (driven by hasChildren, true for all these groups).\r\n * - Hierarchy node (index N): expandable only when there is a further node\r\n * after it (step-by-step drill-down); the deepest node is a leaf, no toggle.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n isLevelExpandable(group: GroupRow, index: number): boolean {\r\n const length = group?.hierarchy?.length ?? 0;\r\n if (index < 0) {\r\n // Group row: a toggle only when it has RELATED groups to show — i.e. the\r\n // hierarchy has more than just the group's own node. A single-node\r\n // hierarchy (only itself) has nothing to reveal, so no toggle.\r\n return length > 1;\r\n }\r\n // Hierarchy node: expandable only if a deeper node follows it.\r\n return index < length - 1;\r\n }\r\n\r\n /**\r\n * Whether the group row shows a toggle (has related hierarchy to drill into).\r\n * @param {GroupRow} group\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n hasHierarchy(group: GroupRow): boolean {\r\n return (group?.hierarchy?.length ?? 0) > 1;\r\n }\r\n\r\n /**\r\n * Whether a given level is currently expanded (its next node is revealed).\r\n * @param {GroupRow} group\r\n * @param {number} index\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n isLevelExpanded(group: GroupRow, index: number): boolean {\r\n return this.expandedKeys.has(this.levelKey(group, index));\r\n }\r\n\r\n /** Convenience for the group row (level -1). */\r\n isGroupExpanded(group: GroupRow): boolean {\r\n return this.isLevelExpanded(group, -1);\r\n }\r\n\r\n /**\r\n * Toggles a level's expansion (reveals/hides its next node). Collapsing a\r\n * level also collapses everything deeper under it so re-opening starts fresh.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @memberof YourGroupsComponent\r\n */\r\n onToggleLevel(group: GroupRow, index: number): void {\r\n if (!this.isLevelExpandable(group, index)) {\r\n return;\r\n }\r\n const key = this.levelKey(group, index);\r\n if (this.expandedKeys.has(key)) {\r\n // Collapse this level and any deeper levels of the same group.\r\n const length = group?.hierarchy?.length ?? 0;\r\n for (let deeper = index; deeper < length; deeper++) {\r\n this.expandedKeys.delete(this.levelKey(group, deeper));\r\n }\r\n } else {\r\n this.expandedKeys.add(key);\r\n }\r\n this.rebuildRows();\r\n }\r\n\r\n /**\r\n * Toggles the card's expanded/collapsed state (whole table visibility) and\r\n * emits the new state so the host's two-way binding stays in sync.\r\n * @memberof YourGroupsComponent\r\n */\r\n onToggleExpand(): void {\r\n this.isExpanded = !this.isExpanded;\r\n this.expandedChange.emit(this.isExpanded);\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" intent for the host.\r\n * @memberof YourGroupsComponent\r\n */\r\n onViewAll(): void {\r\n this.viewAllGroups.emit();\r\n }\r\n\r\n /**\r\n * Re-emits the Material paginator change (page index or \"Items per page\"\r\n * size) as a {@link PageChange} for the host.\r\n * @param {PageEvent} event - The Material paginator event.\r\n * @memberof YourGroupsComponent\r\n */\r\n onPaginatorChange(event: PageEvent): void {\r\n this.pageChange.emit({\r\n pageIndex: event.pageIndex,\r\n pageSize: event.pageSize,\r\n });\r\n }\r\n\r\n /**\r\n * Resolves the member-level pill CSS class, mirroring the My Groups profile\r\n * tab: an assigned level renders green (success), \"Unassigned\" renders amber.\r\n * @param {string} memberLevel\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n resolveBadgeClass(memberLevel: string): string {\r\n const badge = this.texts?.memberLevelBadge;\r\n return memberLevel === this.texts?.unassignedMemberLevel\r\n ? badge?.warning\r\n : badge?.success;\r\n }\r\n\r\n /**\r\n * TrackBy for the rendered table rows.\r\n * @param {number} index\r\n * @param {TableRow} row\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n trackByRow(index: number, row: TableRow): string {\r\n return row.kind === 'group'\r\n ? `g:${row.group?.groupId}`\r\n : `h:${row.group?.groupId}:${row.node?.groupId}:${index}`;\r\n }\r\n\r\n /**\r\n * Rebuilds the visible rows for the current page. Each group reveals its\r\n * hierarchy ONE level at a time (Groups-module style): the group row reveals\r\n * node 0 only when its own level (-1) is expanded; node 0 reveals node 1 only\r\n * when node 0's level is expanded; and so on. Each revealed node that still\r\n * has a child carries its own +/- toggle.\r\n * @memberof YourGroupsComponent\r\n */\r\n private rebuildRows(): void {\r\n const start = this.pageIndex * this.pageSize;\r\n const pageGroups = this.groups.slice(start, start + this.pageSize);\r\n const rows: TableRow[] = [];\r\n\r\n pageGroups.forEach((group) => {\r\n rows.push({ kind: 'group', group, level: 0 });\r\n\r\n const hierarchy = group.hierarchy ?? [];\r\n // Walk the path, revealing each next node only while the chain of\r\n // parent levels above it stays expanded. Stop as soon as a level is\r\n // collapsed.\r\n for (let index = 0; index < hierarchy.length; index++) {\r\n if (!this.isLevelExpanded(group, index - 1)) {\r\n break;\r\n }\r\n rows.push({\r\n kind: 'hierarchy',\r\n group,\r\n node: hierarchy[index],\r\n nodeIndex: index,\r\n level: index + 1,\r\n });\r\n }\r\n });\r\n\r\n this.visibleRows = rows;\r\n }\r\n}\r\n","<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 <!-- Group row toggle (level -1): reveals the first hierarchy\r\n node. Same shared icon button as the Groups tree. -->\r\n <ieeesa-icon-button\r\n *ngIf=\"isLevelExpandable(row.group!, -1)\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [iconButton]=\"getToggleButton(row.group!, -1)\"\r\n [ariaExpanded]=\"isLevelExpanded(row.group!, -1)\"\r\n (iconButtonClick)=\"onToggleLevel(row.group!, -1)\"\r\n ></ieeesa-icon-button>\r\n <!-- Leaf group (no hierarchy): spacer keeps names aligned. -->\r\n <span\r\n *ngIf=\"!isLevelExpandable(row.group!, -1)\"\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 <!-- This node's own +/- toggle, when it has a further child to\r\n reveal (step-by-step drill-down like the Groups tree). -->\r\n <ieeesa-icon-button\r\n *ngIf=\"isLevelExpandable(row.group!, row.nodeIndex!)\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [iconButton]=\"getToggleButton(row.group!, row.nodeIndex!)\"\r\n [ariaExpanded]=\"isLevelExpanded(row.group!, row.nodeIndex!)\"\r\n (iconButtonClick)=\"onToggleLevel(row.group!, row.nodeIndex!)\"\r\n ></ieeesa-icon-button>\r\n <!-- Leaf node: spacer keeps the name aligned with parent nodes\r\n (same footprint as the toggle), no connector arrow. -->\r\n <span\r\n *ngIf=\"!isLevelExpandable(row.group!, row.nodeIndex!)\"\r\n class=\"ieeesa-your-groups__toggle-spacer\"\r\n aria-hidden=\"true\"\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 — 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","/**\r\n * Pure mappers converting the raw \"events & meetings\" backend list/detail items\r\n * into the dashboard view models. No Angular / service dependencies so they are\r\n * trivially unit-testable and shared by {@link DashboardService}.\r\n *\r\n * Backend dates are epoch milliseconds; callers format them with luxon\r\n * `DateTime.fromMillis` at render time. The list mapper enforces the dashboard\r\n * rule that STANDALONE_MEETING rows always sort LAST within the section.\r\n */\r\nimport {\r\n EventMeetingDetailItem,\r\n EventMeetingListItem,\r\n} from '../models/event-meeting-list-item.model';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\nimport { computeDayIndicator } from './date-format.util';\r\n\r\n/**\r\n * Determines whether a raw list item is an EVENT (owns child meetings) or a\r\n * STANDALONE_MEETING. An item is an EVENT when the backend flags it with\r\n * `isMeetingEvent === true` or `hasChildren === true`.\r\n * @param {EventMeetingListItem} item - The raw list item.\r\n * @return {UpcomingItemKind} The resolved render kind.\r\n */\r\nexport function resolveItemKind(\r\n item: EventMeetingListItem\r\n): UpcomingItemKind {\r\n const isEvent = item?.isMeetingEvent === true || item?.hasChildren === true;\r\n return isEvent ? UpcomingItemKind.EVENT : UpcomingItemKind.STANDALONE_MEETING;\r\n}\r\n\r\n/**\r\n * Maps a raw backend list item to the {@link UpcomingEvent} view model. EVENT\r\n * rows start with an empty `meetings` array (child meetings are lazily loaded on\r\n * expand); STANDALONE_MEETING rows carry their own group/location fields.\r\n * @param {EventMeetingListItem} item - The raw list item.\r\n * @return {UpcomingEvent} The mapped view model.\r\n */\r\nexport function mapListItemToUpcomingEvent(\r\n item: EventMeetingListItem\r\n): UpcomingEvent {\r\n const kind = resolveItemKind(item);\r\n const timezone = item?.timeZone ?? '';\r\n const dayIndicator =\r\n item?.dayIndicator ??\r\n (kind === UpcomingItemKind.EVENT\r\n ? computeDayIndicator(item?.startDateTime, item?.endDateTime, timezone)\r\n : '');\r\n return {\r\n eventId: item?.id ?? item?.eventId ?? item?.meetingId ?? '',\r\n kind,\r\n // The list endpoint uses `name`; fall back to `meetingTitle` for meeting rows.\r\n title: item?.name ?? item?.meetingTitle ?? '',\r\n // The list screen copies status into contentUnderLink; accept either.\r\n status: item?.status ?? item?.contentUnderLink ?? '',\r\n dayIndicator,\r\n meetingCount:\r\n kind === UpcomingItemKind.STANDALONE_MEETING\r\n ? 1\r\n : item?.meetingCount ?? 0,\r\n openForAttendanceCount: item?.openForAttendanceCount ?? 0,\r\n startDateTime: item?.startDateTime,\r\n endDateTime: item?.endDateTime,\r\n timezone,\r\n groupOrCommittee: item?.groupName ?? item?.groupAcronym ?? '',\r\n roomOrLocation: item?.meetingLocation ?? item?.room ?? '',\r\n isMemberOfGroup: item?.isMemberOfGroup ?? false,\r\n meetings: [],\r\n };\r\n}\r\n\r\n/**\r\n * Maps a raw backend list of events & meetings into the dashboard view models,\r\n * enforcing that STANDALONE_MEETING rows always sort LAST while preserving the\r\n * backend's within-group ordering for each partition (stable sort).\r\n * @param {EventMeetingListItem[]} items - The raw list items.\r\n * @return {UpcomingEvent[]} The mapped, standalone-last ordered view models.\r\n */\r\nexport function mapEventMeetingList(\r\n items: EventMeetingListItem[]\r\n): UpcomingEvent[] {\r\n const mapped = (items ?? []).map((item) => mapListItemToUpcomingEvent(item));\r\n const events = mapped.filter(\r\n (entry) => entry.kind === UpcomingItemKind.EVENT\r\n );\r\n const standalone = mapped.filter(\r\n (entry) => entry.kind === UpcomingItemKind.STANDALONE_MEETING\r\n );\r\n return [...events, ...standalone];\r\n}\r\n\r\n/**\r\n * Maps a raw backend child-meeting detail item to the {@link MeetingRow} view\r\n * model used by the event block's expanded meeting list.\r\n * @param {EventMeetingDetailItem} item - The raw child-meeting item.\r\n * @return {MeetingRow} The mapped meeting row.\r\n */\r\nexport function mapDetailItemToMeetingRow(\r\n item: EventMeetingDetailItem\r\n): MeetingRow {\r\n const status = item?.status ?? '';\r\n // A meeting is \"open for attendance\" while it is In Progress. The\r\n // meetingsDetails endpoint has no dedicated flag, so derive it from status\r\n // (honouring an explicit backend flag when one is provided).\r\n const isOpenForAttendance =\r\n item?.isOpenForAttendance ?? status.trim().toLowerCase() === 'in progress';\r\n return {\r\n meetingId: item?.meetingId ?? '',\r\n meetingName: item?.meetingTitle ?? '',\r\n groupOrCommittee: item?.groupName ?? '',\r\n roomOrLocation: item?.meetingLocation ?? '',\r\n startDateTime: item?.meetingStDate,\r\n endDateTime: item?.meetingEdDate,\r\n timezone: item?.timeZone ?? '',\r\n status,\r\n isMemberOfGroup: item?.isMemberOfGroup ?? false,\r\n isOpenForAttendance,\r\n };\r\n}\r\n\r\n/**\r\n * Maps a raw backend list of child-meeting detail items to {@link MeetingRow}\r\n * view models.\r\n * @param {EventMeetingDetailItem[]} items - The raw child-meeting items.\r\n * @return {MeetingRow[]} The mapped meeting rows.\r\n */\r\nexport function mapEventMeetingDetails(\r\n items: EventMeetingDetailItem[]\r\n): MeetingRow[] {\r\n return (items ?? []).map((item) => mapDetailItemToMeetingRow(item));\r\n}\r\n","import { AttendanceState } from '../models/attendance-state.model';\r\n\r\n/**\r\n * Pure reducers for the dashboard attendance state. These functions never\r\n * mutate their inputs; each returns a new object/set so they can be exercised\r\n * directly by property tests and composed by the DashboardService.\r\n */\r\n\r\n/**\r\n * Produce a new attendance-state map with the target meeting set to\r\n * CURRENTLY_ATTENDING. Every other entry is copied unchanged (frame property).\r\n *\r\n * @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).\r\n * @param {string} meetingId The meeting whose state transitions to CURRENTLY_ATTENDING.\r\n * @return {Record<string, AttendanceState>} A new map reflecting the successful log-attendance action.\r\n */\r\nexport const applyLogAttendanceSuccess = (\r\n map: Record<string, AttendanceState>,\r\n meetingId: string\r\n): Record<string, AttendanceState> => ({\r\n ...map,\r\n [meetingId]: AttendanceState.CURRENTLY_ATTENDING,\r\n});\r\n\r\n/**\r\n * Produce a new attendance-state map with the target meeting set to\r\n * NOT_ATTENDING. Every other entry is copied unchanged (frame property).\r\n *\r\n * @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).\r\n * @param {string} meetingId The meeting whose state transitions to NOT_ATTENDING.\r\n * @return {Record<string, AttendanceState>} A new map reflecting the successful leave-meeting action.\r\n */\r\nexport const applyLeaveMeetingSuccess = (\r\n map: Record<string, AttendanceState>,\r\n meetingId: string\r\n): Record<string, AttendanceState> => ({\r\n ...map,\r\n [meetingId]: AttendanceState.NOT_ATTENDING,\r\n});\r\n\r\n/**\r\n * Add a meeting to the in-flight set, returning a new set. Prior membership is\r\n * retained so the displayed attendance state is preserved while the request\r\n * resolves.\r\n *\r\n * @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).\r\n * @param {string} meetingId The meeting whose attendance action has started.\r\n * @return {Set<string>} A new set that additionally contains the meeting id.\r\n */\r\nexport const beginAttendanceAction = (\r\n set: ReadonlySet<string>,\r\n meetingId: string\r\n): Set<string> => new Set([...set, meetingId]);\r\n\r\n/**\r\n * Remove a meeting from the in-flight set, returning a new set. All other\r\n * in-flight ids are retained.\r\n *\r\n * @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).\r\n * @param {string} meetingId The meeting whose attendance action has resolved.\r\n * @return {Set<string>} A new set that no longer contains the meeting id.\r\n */\r\nexport const endAttendanceAction = (\r\n set: ReadonlySet<string>,\r\n meetingId: string\r\n): Set<string> => {\r\n const next = new Set(set);\r\n next.delete(meetingId);\r\n return next;\r\n};\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n BehaviorSubject,\r\n Observable,\r\n catchError,\r\n map,\r\n of,\r\n} from 'rxjs';\r\nimport { HttpService } from '@ieeesa-npm/utility';\r\nimport { UserPermission } from '@ieeesa-npm/models';\r\nimport { AttendanceState } from '../models/attendance-state.model';\r\nimport { DashboardListResponse } from '../models/dashboard-list-response.model';\r\nimport { DashboardSectionState } from '../models/dashboard-section-state.model';\r\nimport { GroupRow } from '../models/group-row.model';\r\nimport {\r\n MyGroupsView,\r\n MyGroupView,\r\n} from '../models/my-groups-view.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\nimport {\r\n EventMeetingDetailPayload,\r\n EventMeetingListPayload,\r\n} from '../models/event-meeting-list-payload.model';\r\nimport {\r\n EventMeetingDetailResponse,\r\n EventMeetingListResponse,\r\n} from '../models/event-meeting-list-item.model';\r\nimport {\r\n mapEventMeetingDetails,\r\n mapEventMeetingList,\r\n} from '../utils/event-meeting-mapper.util';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\n\r\n/** Fallback label for an empty group type / member level, matching the My Groups tab. */\r\nconst UNASSIGNED_LABEL = 'Unassigned';\r\n/** Placeholder for an empty cell value. */\r\nconst EMPTY_VALUE = '-';\r\n/** Statuses included in the upcoming section, matching the view-events-meetings-list screen. */\r\nconst UPCOMING_STATUSES = ['In Progress', 'Upcoming'];\r\n/** Sort column used for the top-level events & meetings list. */\r\nconst UPCOMING_SORT_COLUMN = 'startDateTime';\r\n/** Sort column used for an event's expanded child-meeting list (meetingsDetails). */\r\nconst EVENT_MEETINGS_SORT_COLUMN = 'meetingStDate';\r\n/** Default page size for the top-level upcoming section list. */\r\nconst UPCOMING_PAGE_SIZE = 10;\r\n/** Default page size for an event's expanded child-meeting list. */\r\nconst EVENT_MEETINGS_PAGE_SIZE = 5;\r\n/** Large page size used by the eager count prefetch to capture the full set. */\r\nconst EVENT_COUNT_PAGE_SIZE = 200;\r\nimport {\r\n applyLeaveMeetingSuccess,\r\n applyLogAttendanceSuccess,\r\n beginAttendanceAction,\r\n endAttendanceAction,\r\n} from './attendance-reducers';\r\n\r\n/**\r\n * DashboardService is the single source of truth for the dashboard landing\r\n * page's data and attendance state. It mirrors the `events-and-meetings`\r\n * service conventions: it is a `providedIn: 'root'` singleton, holds the host\r\n * `apiBaseUrl` / `userPermissions` set via {@link setAppConfig}, owns its state\r\n * via `BehaviorSubject`s exposed as observables, and reaches the backend only\r\n * through the shared `HttpService` from `@ieeesa-npm/utility` (never\r\n * `HttpClient` directly).\r\n *\r\n * The upcoming-events load calls the real `POST /meetings/eventsAndMeetings`\r\n * endpoint (child meetings are lazily loaded per-event via\r\n * `POST /meetings/meetingsDetails`); the groups load calls `GET\r\n * /groups/my-groups`. The attendance actions compose the pure reducers from\r\n * `attendance-reducers.ts` so the displayed `AttendanceState` only advances on a\r\n * successful resolution and the prior state is retained on failure.\r\n * @export\r\n * @class DashboardService\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class DashboardService {\r\n apiBaseUrl!: string;\r\n userPermissions!: UserPermission[];\r\n\r\n private readonly upcomingEvents = new BehaviorSubject<UpcomingEvent[]>([]);\r\n private readonly groups = new BehaviorSubject<GroupRow[]>([]);\r\n private readonly upcomingState = new BehaviorSubject<DashboardSectionState>(\r\n DashboardSectionState.LOADING\r\n );\r\n private readonly groupsState = new BehaviorSubject<DashboardSectionState>(\r\n DashboardSectionState.LOADING\r\n );\r\n private readonly attendanceStates = new BehaviorSubject<\r\n Record<string, AttendanceState>\r\n >({});\r\n private readonly inFlightMeetingIds = new BehaviorSubject<\r\n ReadonlySet<string>\r\n >(new Set<string>());\r\n\r\n /** Emits the list of the user's upcoming events. */\r\n upcomingEvents$: Observable<UpcomingEvent[]> =\r\n this.upcomingEvents.asObservable();\r\n /** Emits the list of the user's groups. */\r\n groups$: Observable<GroupRow[]> = this.groups.asObservable();\r\n /** Emits the load/empty/error state of the upcoming-events section. */\r\n upcomingState$: Observable<DashboardSectionState> =\r\n this.upcomingState.asObservable();\r\n /** Emits the load/empty/error state of the groups section. */\r\n groupsState$: Observable<DashboardSectionState> =\r\n this.groupsState.asObservable();\r\n /** Emits the per-meeting attendance-state map. */\r\n attendanceStates$: Observable<Record<string, AttendanceState>> =\r\n this.attendanceStates.asObservable();\r\n /** Emits the set of meeting ids with an attendance action in flight. */\r\n inFlightMeetingIds$: Observable<ReadonlySet<string>> =\r\n this.inFlightMeetingIds.asObservable();\r\n\r\n constructor(\r\n // eslint-disable-next-line no-unused-vars\r\n private httpService: HttpService // eslint-disable-next-line no-empty-function\r\n ) {}\r\n\r\n /**\r\n * Stores the host-supplied API base URL and user permissions used to build\r\n * request URLs and gate permission-controlled actions. Mirrors the\r\n * `events-and-meetings` service `setAppConfig`.\r\n * @param {string} apiBaseURL - The host application's API base URL.\r\n * @param {UserPermission[]} userPermissions - The signed-in user's permissions.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n setAppConfig(apiBaseURL: string, userPermissions: UserPermission[]): void {\r\n this.apiBaseUrl = apiBaseURL;\r\n this.userPermissions = userPermissions;\r\n }\r\n\r\n /**\r\n * Loads the user's upcoming events & meetings from the real backend via\r\n * `POST {apiBaseUrl}/meetings/eventsAndMeetings`, the same endpoint the\r\n * `view-events-meetings-list` screen uses. The response is mapped into the\r\n * dashboard view models (with STANDALONE_MEETING rows ordered last), the\r\n * per-meeting attendance-state map is seeded, and the section advances through\r\n * LOADING → LOADED/EMPTY on success, leaving the caller to set ERROR on\r\n * failure. Follows the shared `pipe(map, catchError(throw))` pattern.\r\n * @return {Observable<EventMeetingListResponse>} The upcoming events & meetings response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadUpcomingEvents(): Observable<EventMeetingListResponse> {\r\n this.upcomingState.next(DashboardSectionState.LOADING);\r\n const payload: EventMeetingListPayload = {\r\n payload: {\r\n eventId: null,\r\n sortColumn: UPCOMING_SORT_COLUMN,\r\n ascendingOrder: true,\r\n page: 1,\r\n size: UPCOMING_PAGE_SIZE,\r\n filter: {\r\n status: UPCOMING_STATUSES,\r\n isAllMeetingSelected: false,\r\n },\r\n },\r\n };\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/eventsAndMeetings`, payload)\r\n .pipe(\r\n map((response: EventMeetingListResponse) => {\r\n const events = mapEventMeetingList(\r\n response?.body?.eventMeetingList ?? []\r\n );\r\n this.upcomingEvents.next(events);\r\n this.seedAttendanceStates(events);\r\n this.upcomingState.next(\r\n events.length > 0\r\n ? DashboardSectionState.LOADED\r\n : DashboardSectionState.EMPTY\r\n );\r\n // Eagerly fetch each EVENT's meeting count so the \"{n} meetings\" and\r\n // \"{n} open for attendance\" summaries are correct before expanding.\r\n this.loadEventCounts(events);\r\n return response;\r\n }),\r\n catchError((error) => {\r\n this.upcomingState.next(DashboardSectionState.ERROR);\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Lazily loads (and paginates) the child meetings of an EVENT row via\r\n * `POST {apiBaseUrl}/meetings/meetingsDetails` — the per-event expand endpoint\r\n * used by the reference screen. On success the loaded meetings are mapped and\r\n * merged onto the matching event in the `upcomingEvents` list (with its\r\n * `meetingCount` / `openForAttendanceCount` refreshed), and the per-meeting\r\n * attendance-state map is extended. Each event paginates independently.\r\n * @param {string} eventId - The event whose meetings to load.\r\n * @param {number} [page=1] - The one-based page to request.\r\n * @param {number} [size=EVENT_MEETINGS_PAGE_SIZE] - The page size.\r\n * @return {Observable<EventMeetingDetailResponse>} The child-meetings response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadEventMeetings(\r\n eventId: string,\r\n page = 1,\r\n size = EVENT_MEETINGS_PAGE_SIZE\r\n ): Observable<EventMeetingDetailResponse> {\r\n return this.fetchEventMeetingsPage(eventId, page, size).pipe(\r\n map((response: EventMeetingDetailResponse) => {\r\n const meetings = mapEventMeetingDetails(\r\n response?.body?.meetings ?? []\r\n );\r\n const total = response?.body?.totalRecords ?? meetings.length;\r\n // Prefer the already-known full open count on the event; fall back to\r\n // the current page's open count when it hasn't been prefetched.\r\n const existing = this.upcomingEvents.value.find(\r\n (event) => event.eventId === eventId\r\n );\r\n const pageOpenCount = meetings.filter(\r\n (meeting) => meeting.isOpenForAttendance\r\n ).length;\r\n const openForAttendanceCount =\r\n existing?.openForAttendanceCount || pageOpenCount;\r\n this.mergeEventMeetings(eventId, meetings, total, openForAttendanceCount);\r\n this.seedAttendanceStatesFromMeetings(meetings);\r\n return response;\r\n }),\r\n catchError((error) => {\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Merges a freshly loaded page of child meetings onto the matching event in\r\n * the `upcomingEvents` list, refreshing the event's `meetings`,\r\n * `meetingCount` (from the backend `totalRecords`), and\r\n * `openForAttendanceCount`. Leaves all other events untouched.\r\n * @param {string} eventId - The event to merge meetings onto.\r\n * @param {MeetingRow[]} meetings - The mapped child meetings for the page.\r\n * @param {number} totalRecords - The event's total meeting count from the backend.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private mergeEventMeetings(\r\n eventId: string,\r\n meetings: MeetingRow[],\r\n totalRecords: number,\r\n openForAttendanceCount: number\r\n ): void {\r\n const next = this.upcomingEvents.value.map((event) => {\r\n if (event.eventId !== eventId) {\r\n return event;\r\n }\r\n return {\r\n ...event,\r\n meetings,\r\n meetingCount: totalRecords,\r\n openForAttendanceCount,\r\n };\r\n });\r\n this.upcomingEvents.next(next);\r\n }\r\n\r\n /**\r\n * Eagerly fetches each EVENT's total meeting count and open-for-attendance\r\n * count by requesting a large first page of its child meetings, then merging\r\n * only the counts (not the rows) so the collapsed card summaries are accurate\r\n * before the user expands. Standalone meetings are skipped. Failures per event\r\n * are swallowed so one failing count never breaks the list.\r\n * @param {UpcomingEvent[]} events - The loaded events to fetch counts for.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private loadEventCounts(events: UpcomingEvent[]): void {\r\n events\r\n .filter((event) => event.kind === UpcomingItemKind.EVENT && event.eventId)\r\n .forEach((event) => {\r\n this.fetchEventMeetingsPage(event.eventId, 1, EVENT_COUNT_PAGE_SIZE)\r\n .pipe(\r\n catchError(() => of(null))\r\n )\r\n .subscribe((response) => {\r\n if (!response) {\r\n return;\r\n }\r\n const meetings = mapEventMeetingDetails(\r\n response?.body?.meetings ?? []\r\n );\r\n const total = response?.body?.totalRecords ?? meetings.length;\r\n const openCount = meetings.filter(\r\n (meeting) => meeting.isOpenForAttendance\r\n ).length;\r\n this.mergeEventCounts(event.eventId, total, openCount);\r\n this.seedAttendanceStatesFromMeetings(meetings);\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Merges only the meeting counts onto the matching event, leaving its\r\n * `meetings` rows untouched (used by the eager count prefetch).\r\n * @param {string} eventId - The event to update.\r\n * @param {number} totalRecords - The event's total meeting count.\r\n * @param {number} openForAttendanceCount - The open-for-attendance count.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private mergeEventCounts(\r\n eventId: string,\r\n totalRecords: number,\r\n openForAttendanceCount: number\r\n ): void {\r\n const next = this.upcomingEvents.value.map((event) =>\r\n event.eventId === eventId\r\n ? { ...event, meetingCount: totalRecords, openForAttendanceCount }\r\n : event\r\n );\r\n this.upcomingEvents.next(next);\r\n }\r\n\r\n /**\r\n * Builds and posts the `meetingsDetails` request for a single event page,\r\n * returning the raw response envelope. Shared by {@link loadEventMeetings} and\r\n * the eager count prefetch.\r\n * @param {string} eventId - The event whose meetings to fetch.\r\n * @param {number} page - The one-based page to request.\r\n * @param {number} size - The page size.\r\n * @return {Observable<EventMeetingDetailResponse>} The child-meetings response.\r\n * @memberof DashboardService\r\n */\r\n private fetchEventMeetingsPage(\r\n eventId: string,\r\n page: number,\r\n size: number\r\n ): Observable<EventMeetingDetailResponse> {\r\n const payload: EventMeetingDetailPayload = {\r\n payload: {\r\n eventId,\r\n sortColumn: EVENT_MEETINGS_SORT_COLUMN,\r\n ascendingOrder: true,\r\n page,\r\n size,\r\n filter: {\r\n status: UPCOMING_STATUSES,\r\n isAllMeetingSelected: false,\r\n },\r\n },\r\n };\r\n return this.httpService.postData(\r\n `${this.apiBaseUrl}/meetings/meetingsDetails`,\r\n payload\r\n );\r\n }\r\n\r\n /**\r\n * Loads the user's groups, driving the groups section through\r\n * LOADING → LOADED/EMPTY on success and leaving the caller to set ERROR on\r\n * failure. Follows the `pipe(map, catchError(throw))` pattern.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n * @return {Observable<DashboardListResponse<GroupRow[]>>} The groups response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadGroups(): Observable<DashboardListResponse<MyGroupsView>> {\r\n this.groupsState.next(DashboardSectionState.LOADING);\r\n return this.httpService\r\n .getData(`${this.apiBaseUrl}/groups/my-groups`)\r\n .pipe(\r\n map((response: DashboardListResponse<MyGroupsView>) => {\r\n const groups = (response?.body?.groups ?? []).map((group) =>\r\n this.mapGroup(group)\r\n );\r\n this.groups.next(groups);\r\n this.groupsState.next(\r\n groups.length > 0\r\n ? DashboardSectionState.LOADED\r\n : DashboardSectionState.EMPTY\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n this.groupsState.next(DashboardSectionState.ERROR);\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Maps a backend {@link MyGroupView} to the table-facing {@link GroupRow}.\r\n * Mirrors the My Groups profile tab: the type falls back to \"Unassigned\" when\r\n * `groupTypeName` is null, affiliations are comma-joined, empty officer role /\r\n * affiliation render as a placeholder, and a blank member level becomes\r\n * \"Unassigned\" (rendered as the warning pill by the Your Groups component).\r\n * @param {MyGroupView} group - The backend group view.\r\n * @return {GroupRow}\r\n * @memberof DashboardService\r\n */\r\n private mapGroup(group: MyGroupView): GroupRow {\r\n // The backend returns officer roles as an `officer` array of\r\n // { officerId, officerName }. Join the names for the Officer Role column\r\n // (e.g. \"Chair\" or \"Chair, Vice Chair\"); show the placeholder when empty.\r\n const officerRole =\r\n (group.officer ?? [])\r\n .map((officer) => officer?.officerName?.trim())\r\n .filter((name) => !!name)\r\n .join(', ') || EMPTY_VALUE;\r\n\r\n return {\r\n groupId: group.groupId,\r\n group: group.groupName,\r\n type: group.groupTypeName || group.groupType || UNASSIGNED_LABEL,\r\n officerRole,\r\n affiliation: group.affiliations?.join(', ') || EMPTY_VALUE,\r\n memberLevel: group.memberLevel?.trim() || UNASSIGNED_LABEL,\r\n // Carry the ancestor hierarchy through for the expandable hierarchy rows.\r\n hierarchy: group.hierarchy ?? [],\r\n };\r\n }\r\n\r\n /**\r\n * Logs attendance for a meeting. Marks the meeting in-flight (retaining the\r\n * prior displayed state), posts through `HttpService`, applies the\r\n * log-attendance-success reducer on success, clears the in-flight flag on\r\n * completion, and rethrows while retaining prior state on failure.\r\n * @param {string} meetingId - The meeting to log attendance for.\r\n * @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.\r\n * @memberof DashboardService\r\n */\r\n logAttendance(\r\n meetingId: string\r\n ): Observable<DashboardListResponse<unknown>> {\r\n this.inFlightMeetingIds.next(\r\n beginAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/attendance/log`, { meetingId })\r\n .pipe(\r\n map((response) => {\r\n this.attendanceStates.next(\r\n applyLogAttendanceSuccess(this.attendanceStates.value, meetingId)\r\n );\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n // Retain prior attendance state; only clear the in-flight flag.\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Leaves a meeting. Marks the meeting in-flight (retaining the prior\r\n * displayed state), posts through `HttpService`, applies the\r\n * leave-meeting-success reducer on success, clears the in-flight flag on\r\n * completion, and rethrows while retaining prior state on failure.\r\n * @param {string} meetingId - The meeting to leave.\r\n * @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.\r\n * @memberof DashboardService\r\n */\r\n leaveMeeting(\r\n meetingId: string\r\n ): Observable<DashboardListResponse<unknown>> {\r\n this.inFlightMeetingIds.next(\r\n beginAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/attendance/leave`, { meetingId })\r\n .pipe(\r\n map((response) => {\r\n this.attendanceStates.next(\r\n applyLeaveMeetingSuccess(this.attendanceStates.value, meetingId)\r\n );\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n // Retain prior attendance state; only clear the in-flight flag.\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Returns a synchronous snapshot of the per-meeting attendance-state map.\r\n * @return {Record<string, AttendanceState>} The current attendance-state map.\r\n * @memberof DashboardService\r\n */\r\n getAttendanceStatesSnapshot(): Record<string, AttendanceState> {\r\n return this.attendanceStates.value;\r\n }\r\n\r\n /**\r\n * Seeds the attendance-state map from a freshly loaded list of events, using\r\n * each meeting's `attendanceState` (defaulting to `NOT_ATTENDING`). Keeps the\r\n * displayed state in sync with the data load without overwriting ids that are\r\n * not present in the new list.\r\n * @param {UpcomingEvent[]} events - The loaded upcoming events.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private seedAttendanceStates(events: UpcomingEvent[]): void {\r\n const meetings = events.flatMap((event) => event.meetings ?? []);\r\n this.seedAttendanceStatesFromMeetings(meetings);\r\n }\r\n\r\n /**\r\n * Seeds the attendance-state map from a list of meeting rows, using each\r\n * meeting's `attendanceState` (defaulting to `NOT_ATTENDING`) without\r\n * overwriting ids absent from the new list. Shared by the list load and the\r\n * per-event expand so freshly loaded child meetings pick up their state.\r\n * @param {MeetingRow[]} meetings - The meeting rows to seed from.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private seedAttendanceStatesFromMeetings(meetings: MeetingRow[]): void {\r\n const next: Record<string, AttendanceState> = {\r\n ...this.attendanceStates.value,\r\n };\r\n meetings.forEach((meeting) => {\r\n if (meeting.meetingId) {\r\n next[meeting.meetingId] =\r\n meeting.attendanceState ??\r\n next[meeting.meetingId] ??\r\n AttendanceState.NOT_ATTENDING;\r\n }\r\n });\r\n this.attendanceStates.next(next);\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { UserPermission } from '@ieeesa-npm/models';\r\nimport { AttendanceActionPermissions } from '../models/attendance-action-permissions.model';\r\n\r\n/**\r\n * Permission identifiers (by name) that gate the dashboard attendance actions.\r\n * Mirrors the permission-type pattern used by the `events-and-meetings` and\r\n * `groups` user-permissions services.\r\n */\r\n/* eslint-disable no-unused-vars */\r\nexport enum DashboardPermissionType {\r\n LOG_ATTENDANCE = 'Log Attendance',\r\n LEAVE_MEETING = 'Leave Meeting',\r\n}\r\n/* eslint-enable no-unused-vars */\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class UserPermissionsService {\r\n /**\r\n * Returns access provision for the passed action/feature based on whether the signed in user has appropriate permission.\r\n * @param {DashboardPermissionType} permission\r\n * @param {UserPermission[]} userPermissions\r\n * @return {boolean}\r\n * @memberof UserPermissionsService\r\n */\r\n validateAccessPermission(\r\n permission: DashboardPermissionType,\r\n userPermissions: UserPermission[]\r\n ): boolean {\r\n const isPermitted =\r\n userPermissions?.length > 0\r\n ? userPermissions?.some(\r\n ({ permissionName }) => permissionName === permission\r\n )\r\n : false;\r\n return isPermitted;\r\n }\r\n\r\n /**\r\n * Maps the host-supplied user permissions to the attendance-action permissions consumed by the dashboard rows.\r\n * @param {UserPermission[]} userPermissions\r\n * @return {AttendanceActionPermissions}\r\n * @memberof UserPermissionsService\r\n */\r\n mapToAttendanceActionPermissions(\r\n userPermissions: UserPermission[]\r\n ): AttendanceActionPermissions {\r\n return {\r\n canLogAttendance: this.validateAccessPermission(\r\n DashboardPermissionType.LOG_ATTENDANCE,\r\n userPermissions\r\n ),\r\n canLeaveMeeting: this.validateAccessPermission(\r\n DashboardPermissionType.LEAVE_MEETING,\r\n userPermissions\r\n ),\r\n };\r\n }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n Output,\r\n ViewChild,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { Subject, takeUntil } from 'rxjs';\r\nimport { BreakpointObserverService } from '@ieeesa-npm/presentation';\r\nimport { AlertType, UserPermission } from '@ieeesa-npm/models';\r\nimport { AlertsService } from '@ieeesa-npm/utility';\r\nimport { AttendanceActionPermissions } from './models/attendance-action-permissions.model';\r\nimport { AttendanceState } from './models/attendance-state.model';\r\nimport { DashboardRouteConfig } from './models/dashboard-route-config.model';\r\nimport { DashboardSectionState } from './models/dashboard-section-state.model';\r\nimport { DashboardUserInfo } from './models/dashboard-user-info.model';\r\nimport { GroupRow } from './models/group-row.model';\r\nimport { PageChange } from './models/page-change.model';\r\nimport { UpcomingEvent } from './models/upcoming-event.model';\r\nimport { DashboardService } from './services/dashboard.service';\r\nimport { UserPermissionsService } from './services/user-permissions.service';\r\nimport { UpcomingMeetingsEventsComponent } from './components/upcoming-meetings-events/upcoming-meetings-events.component';\r\nimport * as constants from './assets/constants.json';\r\nimport {\r\n DashboardJumpTarget,\r\n DashboardWelcomeHeaderComponent,\r\n} from './components/welcome-header/dashboard-welcome-header.component';\r\nimport { YourGroupsComponent } from './components/your-groups/your-groups.component';\r\n\r\n/**\r\n * A navigation intent emitted by {@link DashboardComponent} for the host\r\n * application to act on. The library never performs navigation itself; it emits\r\n * the resolved target `path` (from the {@link DashboardRouteConfig}) together\r\n * with the triggering identifier so the host can route accordingly (Req 11.1).\r\n */\r\nexport interface DashboardNavigationIntent {\r\n /** The resolved target route path from the active {@link DashboardRouteConfig}. */\r\n path: string;\r\n /** The identifier that triggered the navigation (event/meeting/group id), when applicable. */\r\n id?: string;\r\n}\r\n\r\n/**\r\n * Dashboard (`ieeesa-dashboard`) is the root container and single host entry\r\n * point for the \"NESC Revision Cycle\" dashboard landing page. It owns the\r\n * host-supplied configuration (`routePaths`, `apiBaseURL`, `userInfo`,\r\n * `userPermissions`), composes the four regions — welcome header, upcoming\r\n * meetings & events, your groups, and footer — and orchestrates data loading\r\n * and attendance actions through the {@link DashboardService}.\r\n *\r\n * The component is composition-first and host-agnostic: it subscribes to the\r\n * service observables (`upcomingEvents$`, `groups$`, the per-section states, the\r\n * attendance-state map, and the in-flight set) with `takeUntil(destroy$)` and\r\n * tracks `isMobileView` from the Presentation_Library\r\n * {@link BreakpointObserverService} (Req 13.1, 13.2, 13.5, 15.1, 15.2). Child\r\n * navigation `@Output()`s are composed into a single {@link dashboardNavigate}\r\n * stream of `{ path, id }` intents resolved from `routePaths` (falling back to\r\n * the default route configuration in `constants.json` when `routePaths` is\r\n * omitted) (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1, 11.5). Attendance `@Output()`s\r\n * are delegated to the service, and on failure the attendance-action error\r\n * message from `constants.json` is surfaced via the shared {@link AlertsService}\r\n * (Req 7.7, 7.8, 13.7). Per-row {@link AttendanceActionPermissions} are computed\r\n * from `userPermissions` and passed down to the rows (Req 12.3).\r\n * @export\r\n * @class DashboardComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-dashboard',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n UpcomingMeetingsEventsComponent,\r\n YourGroupsComponent,\r\n DashboardWelcomeHeaderComponent\r\n ],\r\n templateUrl: './dashboard.component.html',\r\n styleUrls: ['./dashboard.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n providers: [AlertsService],\r\n})\r\nexport class DashboardComponent implements OnInit, OnDestroy {\r\n /** User-facing strings and the default route config sourced from `constants.json`. */\r\n constants = constants;\r\n\r\n /** Host navigation paths; falls back to the `constants.json` default when omitted (Req 11.1, 11.5). */\r\n @Input() routePaths?: DashboardRouteConfig;\r\n\r\n /** The host application's API base URL, forwarded to the service (Req 11.2). */\r\n @Input() apiBaseURL!: string;\r\n\r\n /** The signed-in user's info used by the welcome header greeting (Req 11.3, 4.1). */\r\n @Input() userInfo!: DashboardUserInfo;\r\n\r\n /** The signed-in user's permissions used to gate attendance actions (Req 11.4, 12.3). */\r\n @Input() userPermissions!: UserPermission[];\r\n\r\n /** Emits a resolved navigation intent for the host to act on (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1). */\r\n @Output() dashboardNavigate = new EventEmitter<DashboardNavigationIntent>();\r\n\r\n /** The user's upcoming events, bound to the upcoming section (Req 13.1, 13.2). */\r\n upcomingEvents: UpcomingEvent[] = [];\r\n\r\n /** The user's groups, bound to the groups section (Req 13.1, 13.2). */\r\n groups: GroupRow[] = [];\r\n\r\n /** The upcoming-events section's load/empty/error state (Req 13.1, 13.2, 13.5). */\r\n upcomingState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** The groups section's load/empty/error state (Req 13.1, 13.2, 13.5). */\r\n groupsState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** The per-meeting attendance-state map passed down to the rows. */\r\n attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** The set of meeting ids with an attendance action awaiting resolution. */\r\n inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** The per-row attendance-action permissions derived from `userPermissions` (Req 12.3). */\r\n attendancePermissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Whether the viewport is at/below the mobile breakpoint (Req 15.1, 15.2). */\r\n isMobileView = false;\r\n\r\n /** Whether the Upcoming Meetings & Events card is expanded. Starts collapsed. */\r\n meetingsExpanded = false;\r\n\r\n /** Whether the Your Groups card is expanded. Starts collapsed. */\r\n groupsExpanded = false;\r\n\r\n /**\r\n * Section host elements used to scroll a \"Jump to\" target into view. Read as\r\n * ElementRef (not the component instance) so the native element is available\r\n * for scrollIntoView.\r\n */\r\n @ViewChild('upcomingSection', { read: ElementRef })\r\n upcomingSection?: ElementRef<HTMLElement>;\r\n @ViewChild('groupsSection', { read: ElementRef })\r\n groupsSection?: ElementRef<HTMLElement>;\r\n\r\n /**\r\n * Total number of meetings across the loaded upcoming events, shown in the\r\n * welcome header's \"Upcoming Meetings & Events\" shortcut badge.\r\n * @readonly\r\n * @memberof DashboardComponent\r\n */\r\n get meetingsCount(): number {\r\n return this.upcomingEvents.reduce(\r\n (total, event) => total + (event?.meetingCount ?? 0),\r\n 0\r\n );\r\n }\r\n\r\n /**\r\n * Number of loaded groups, shown in the welcome header's \"Your Groups\"\r\n * shortcut badge.\r\n * @readonly\r\n * @memberof DashboardComponent\r\n */\r\n get groupsCount(): number {\r\n return this.groups.length;\r\n }\r\n\r\n /** The current zero-based page index of the groups table. */\r\n groupsPageIndex = 0;\r\n\r\n /** The current page size of the groups table (5 rows per page per the design). */\r\n groupsPageSize = 5;\r\n\r\n /** Completes on destroy to tear down all subscriptions (Req 2.4, 2.5). */\r\n private readonly destroy$ = new Subject<boolean>();\r\n\r\n constructor(\r\n // eslint-disable-next-line no-unused-vars\r\n private dashboardService: DashboardService,\r\n // eslint-disable-next-line no-unused-vars\r\n private userPermissionsService: UserPermissionsService,\r\n // eslint-disable-next-line no-unused-vars\r\n private breakpointObserverService: BreakpointObserverService,\r\n // eslint-disable-next-line no-unused-vars\r\n private alertService: AlertsService // eslint-disable-next-line no-empty-function\r\n ) {}\r\n\r\n /**\r\n * Initializes the dashboard: forwards the host config to the service, derives\r\n * the per-row attendance permissions, kicks off the upcoming-events and groups\r\n * loads, and wires up subscriptions to the service state observables and the\r\n * breakpoint observer — all cleaned up via `takeUntil(destroy$)` (Req 11.2,\r\n * 11.4, 12.3, 13.1, 13.2, 13.5, 15.1, 15.2).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n ngOnInit(): void {\r\n this.dashboardService.setAppConfig(this.apiBaseURL, this.userPermissions);\r\n this.attendancePermissions =\r\n this.userPermissionsService.mapToAttendanceActionPermissions(\r\n this.userPermissions\r\n );\r\n\r\n this.subscribeToServiceState();\r\n this.subscribeToBreakpoint();\r\n this.loadUpcomingEvents();\r\n this.loadGroups();\r\n }\r\n\r\n /**\r\n * Tears down all subscriptions on destroy (Req 2.4, 2.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n ngOnDestroy(): void {\r\n this.destroy$.next(true);\r\n this.destroy$.complete();\r\n }\r\n\r\n /**\r\n * Handles the welcome-header \"Jump to\" date selection. The dashboard currently\r\n * has no date-scoped data load, so the selection is accepted without side\r\n * effects; the hook keeps the header's contract satisfied for future filtering.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onJumpToDateSelected(): void {\r\n // No date-scoped reload yet; retained for future date filtering (Req 4.4).\r\n }\r\n\r\n /**\r\n * Handles a welcome-header \"Jump to\" shortcut: opens the matching section's\r\n * card (so its content is visible) and smoothly scrolls it into view. It does\r\n * NOT navigate away — the shortcut is an in-page jump to the section.\r\n * @param {DashboardJumpTarget} target - The selected shortcut target.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onJumpToShortcut(target: DashboardJumpTarget): void {\r\n const section =\r\n target === DashboardJumpTarget.MEETINGS\r\n ? this.upcomingSection\r\n : this.groupsSection;\r\n\r\n if (target === DashboardJumpTarget.MEETINGS) {\r\n this.meetingsExpanded = true;\r\n } else {\r\n this.groupsExpanded = true;\r\n }\r\n\r\n // Scroll after the expand has rendered so the target's final position is used.\r\n setTimeout(() => {\r\n section?.nativeElement?.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'start',\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" upcoming-events navigation intent, targeting the\r\n * `viewAllEvents` route with no id (Req 5.2, 11.1).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewAllEvents(): void {\r\n this.emitNavigation(this.activeRouteConfig.viewAllEvents);\r\n }\r\n\r\n /**\r\n * Emits the \"View Event\" navigation intent, targeting the `eventDetail` route\r\n * with the event id (Req 6.4, 11.1).\r\n * @param {string} eventId - The id of the event to view.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewEvent(eventId: string): void {\r\n this.emitNavigation(this.activeRouteConfig.eventDetail, eventId);\r\n }\r\n\r\n /**\r\n * Emits the open-meeting navigation intent, targeting the `meetingDetail`\r\n * route with the meeting id (Req 7.4, 11.1).\r\n * @param {string} meetingId - The id of the meeting to open.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.emitNavigation(this.activeRouteConfig.meetingDetail, meetingId);\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" groups navigation intent, targeting the\r\n * `viewAllGroups` route with no id (Req 8.2, 11.1).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewAllGroups(): void {\r\n this.emitNavigation(this.activeRouteConfig.viewAllGroups);\r\n }\r\n\r\n /**\r\n * Emits the group-detail navigation intent, targeting the `groupDetail` route\r\n * with the group id (Req 8.7, 11.1).\r\n * @param {string} groupId - The id of the selected group.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onGroupSelected(groupId: string): void {\r\n this.emitNavigation(this.activeRouteConfig.groupDetail, groupId);\r\n }\r\n\r\n /**\r\n * Updates the groups table paging state in response to a paginator change so\r\n * the groups section reflects the requested page (Req 8.10).\r\n * @param {PageChange} page - The requested page index and size.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onGroupsPageChange(page: PageChange): void {\r\n this.groupsPageIndex = page.pageIndex;\r\n this.groupsPageSize = page.pageSize;\r\n }\r\n\r\n /**\r\n * Lazily loads (or paginates) the child meetings of an expanded EVENT card via\r\n * the service, surfacing the attendance error message on failure. Each event\r\n * paginates independently.\r\n * @param {{ eventId: string; page: number }} request - The event id and one-based page to load.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLoadEventMeetings(request: { eventId: string; page: number }): void {\r\n if (!request?.eventId) {\r\n return;\r\n }\r\n this.dashboardService\r\n .loadEventMeetings(request.eventId, request.page)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * Delegates a log-attendance request to the service, surfacing the\r\n * attendance-action error message via the shared {@link AlertsService} on\r\n * failure while the service retains the prior displayed state (Req 7.7, 13.7).\r\n * @param {string} meetingId - The meeting to log attendance for.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.dashboardService\r\n .logAttendance(meetingId)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * Delegates a leave-meeting request to the service, surfacing the\r\n * attendance-action error message via the shared {@link AlertsService} on\r\n * failure while the service retains the prior displayed state (Req 7.8, 13.7).\r\n * @param {string} meetingId - The meeting to leave.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.dashboardService\r\n .leaveMeeting(meetingId)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * The route configuration in effect: the host-supplied `routePaths` when\r\n * provided, otherwise the default route config from `constants.json` so\r\n * navigation intents always carry valid targets (Req 11.1, 11.5).\r\n * @return {DashboardRouteConfig} The active route configuration.\r\n * @memberof DashboardComponent\r\n */\r\n private get activeRouteConfig(): DashboardRouteConfig {\r\n return this.routePaths ?? this.constants.defaultRouteConfig;\r\n }\r\n\r\n /**\r\n * Subscribes to the service's state observables, mirroring each into a local\r\n * field for the template to bind. All subscriptions are torn down via\r\n * `takeUntil(destroy$)` (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private subscribeToServiceState(): void {\r\n this.dashboardService.upcomingEvents$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((events) => (this.upcomingEvents = events));\r\n\r\n this.dashboardService.groups$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((groups) => {\r\n this.groups = groups;\r\n });\r\n\r\n this.dashboardService.upcomingState$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((state) => (this.upcomingState = state));\r\n\r\n this.dashboardService.groupsState$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((state) => (this.groupsState = state));\r\n\r\n this.dashboardService.attendanceStates$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((states) => (this.attendanceStates = states));\r\n\r\n this.dashboardService.inFlightMeetingIds$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((ids) => (this.inFlightMeetingIds = ids));\r\n }\r\n\r\n /**\r\n * Subscribes to the Presentation_Library breakpoint observer to keep\r\n * `isMobileView` in sync with the viewport (Req 15.1, 15.2).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private subscribeToBreakpoint(): void {\r\n this.breakpointObserverService\r\n .getBreakpoint()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((result: { matches: boolean }) => {\r\n this.isMobileView = result?.matches;\r\n });\r\n }\r\n\r\n /**\r\n * Triggers the upcoming-events load, setting the section to `ERROR` on failure\r\n * so only the section error region renders (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private loadUpcomingEvents(): void {\r\n this.dashboardService\r\n .loadUpcomingEvents()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => (this.upcomingState = DashboardSectionState.ERROR),\r\n });\r\n }\r\n\r\n /**\r\n * Triggers the groups load, setting the section to `ERROR` on failure so only\r\n * the section error region renders. Isolated from the upcoming-events load so\r\n * one failing does not affect the other (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private loadGroups(): void {\r\n this.dashboardService\r\n .loadGroups()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => (this.groupsState = DashboardSectionState.ERROR),\r\n });\r\n }\r\n\r\n /**\r\n * Composes and emits a {@link DashboardNavigationIntent} for the host from the\r\n * resolved target path and an optional triggering id (Req 11.1).\r\n * @param {string} path - The resolved target route path.\r\n * @param {string} [id] - The triggering identifier, when applicable.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private emitNavigation(path: string, id?: string): void {\r\n this.dashboardNavigate.emit(id ? { path, id } : { path });\r\n }\r\n\r\n /**\r\n * Surfaces the attendance-action error message from `constants.json` via the\r\n * shared {@link AlertsService} (Req 13.7).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private showAttendanceError(): void {\r\n this.alertService?.showMessage({\r\n status: 'custom',\r\n message:\r\n this.constants?.attendance?.errorMessage ??\r\n 'Unable to update your attendance. Please try again.',\r\n alertType: AlertType.ERROR,\r\n isCloseNeeded: true,\r\n });\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport { Component, Input, ViewEncapsulation } from '@angular/core';\r\nimport { Legend, LegendComponent } from '@ieeesa-npm/presentation';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * Member_Level_Badge renders a single member-level value as a colored pill.\r\n * It reuses the Presentation_Library Legend component for the pill primitive,\r\n * sourcing the level-to-color mapping from `constants.json` (`memberLevel.colorMap`)\r\n * with a nullish-coalescing fallback to the configured default color.\r\n * @export\r\n * @class MemberLevelBadgeComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-member-level-badge',\r\n standalone: true,\r\n imports: [CommonModule, LegendComponent],\r\n templateUrl: './member-level-badge.component.html',\r\n styleUrls: ['./member-level-badge.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class MemberLevelBadgeComponent {\r\n constants = constants;\r\n\r\n private memberLevelValue = '';\r\n\r\n @Input()\r\n set memberLevel(value: string) {\r\n this.memberLevelValue = value ?? '';\r\n this.legends = this.buildLegends(this.memberLevelValue);\r\n }\r\n get memberLevel(): string {\r\n return this.memberLevelValue;\r\n }\r\n\r\n /** The Legend input consumed by the Presentation_Library Legend component. */\r\n legends: Legend[] = this.buildLegends('');\r\n\r\n /**\r\n * Builds the single-item Legend list for the supplied member level, resolving\r\n * the pill color from the `constants.json` color map and falling back to the\r\n * configured default color when the level has no explicit mapping.\r\n * @param {string} memberLevel - The member-level label to render.\r\n * @return {Legend[]} A single-element Legend array for the Legend component.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private buildLegends(memberLevel: string): Legend[] {\r\n return [\r\n {\r\n label: memberLevel,\r\n color: this.resolveColorClass(memberLevel),\r\n hierarchy: 0,\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Resolves the CSS modifier class for a member level from the `constants.json`\r\n * color map, using the `??` fallback to the `default` entry when the level is\r\n * missing from the map.\r\n * @param {string} memberLevel - The member-level label to resolve a color for.\r\n * @return {string} The CSS modifier class applied to the pill.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private resolveColorClass(memberLevel: string): string {\r\n const colorMap = this.constants?.memberLevel?.colorMap as\r\n | Record<string, string>\r\n | undefined;\r\n const token =\r\n colorMap?.[memberLevel] ?? colorMap?.['default'] ?? '$ieeesa-color-neutral';\r\n return this.toColorClass(token);\r\n }\r\n\r\n /**\r\n * Converts a shared-styles color token (for example `$ieeesa-color-success`)\r\n * into a valid BEM-style CSS modifier class defined in this component's SCSS.\r\n * @param {string} token - The color token from the color map.\r\n * @return {string} A valid CSS class name.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private toColorClass(token: string): string {\r\n const normalized = token.replace(/^\\$ieeesa-color-/, '').replace(/^\\$/, '');\r\n return `ieeesa-member-level-badge--${normalized || 'neutral'}`;\r\n }\r\n}\r\n","<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","import { NgModule } from '@angular/core';\r\nimport { DashboardComponent } from './dashboard.component';\r\n\r\n@NgModule({\r\n imports: [DashboardComponent],\r\n exports: [DashboardComponent],\r\n})\r\nexport class DashboardModule {}\r\n","import { Routes } from '@angular/router';\r\n\r\nexport const DASHBOARD_ROUTES: Routes = [\r\n {\r\n path: '',\r\n loadComponent: () =>\r\n import('./dashboard.component').then((m) => m.DashboardComponent),\r\n },\r\n];\r\n","/**\r\n * Request payloads for the dashboard \"events & meetings\" backend calls. These\r\n * mirror the `events-and-meetings` library's `GetEventsAndMeetingsPayload` /\r\n * `GetMeetingsByEventIdPayload` so the dashboard reuses the exact contract the\r\n * existing `view-events-meetings-list` screen posts.\r\n */\r\n\r\n/** Filter block shared by the list and expand payloads. */\r\nexport interface EventMeetingFilter {\r\n /** Lifecycle statuses to include, e.g. [\"In Progress\", \"Upcoming\"]. */\r\n status: string[];\r\n /** Whether every meeting (regardless of membership) should be returned. */\r\n isAllMeetingSelected: boolean;\r\n /** Optional group-id scope. */\r\n groupIds?: string[];\r\n}\r\n\r\n/** Payload for `POST {apiBaseUrl}/meetings/eventsAndMeetings` (the section list). */\r\nexport interface EventMeetingListPayload {\r\n payload: {\r\n /** Null for the top-level list; an event id when scoping to one event. */\r\n eventId: string | null;\r\n sortColumn: string;\r\n ascendingOrder: boolean;\r\n page: number;\r\n size: number;\r\n searchTerm?: string | null;\r\n filter: EventMeetingFilter;\r\n };\r\n}\r\n\r\n/** Payload for `POST {apiBaseUrl}/meetings/meetingsDetails` (per-event expand). */\r\nexport interface EventMeetingDetailPayload {\r\n payload: {\r\n eventId: string;\r\n sortColumn: string;\r\n ascendingOrder: boolean;\r\n page: number;\r\n size: number;\r\n searchTerm?: string | null;\r\n filter: EventMeetingFilter;\r\n };\r\n}\r\n","import { DashboardRouteConfig } from '../models/dashboard-route-config.model';\r\n\r\nexport const DashboardRoutePathsMock: DashboardRouteConfig = {\r\n eventDetail: 'events-and-meetings/view-event',\r\n meetingDetail: 'events-and-meetings/view-meeting',\r\n /*\r\n * The demo app only registers a flat `groups` route (no group-detail screen),\r\n * so group-row navigation targets it rather than a `view-group` child that the\r\n * demo does not implement. A consuming app with a real group-detail route\r\n * supplies its own path via the `routePaths` input.\r\n */\r\n groupDetail: 'groups',\r\n viewAllEvents: 'events-and-meetings/view-events-meetings-list',\r\n viewAllGroups: 'groups',\r\n};\r\n","import { UserPermission } from '@ieeesa-npm/models';\r\n\r\nexport const DashboardUserPermissionsMock: UserPermission[] = [\r\n {\r\n permissionName: 'View Events',\r\n permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',\r\n },\r\n {\r\n permissionName: 'View Meetings',\r\n permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',\r\n },\r\n {\r\n permissionName: 'View Groups',\r\n permissionId: 'PERM_9a1f0c84-2b77-4e2a-9f3d-1c6b4e9a8d20',\r\n },\r\n {\r\n permissionName: 'Log Attendance',\r\n permissionId: 'PERM_1b2c3d4e-5f60-4718-8293-aabbccddeeff',\r\n },\r\n {\r\n permissionName: 'Leave Meeting',\r\n permissionId: 'PERM_6f5e4d3c-2b1a-4908-8716-ffeeddccbbaa',\r\n },\r\n];\r\n","import { AttendanceState } from '../models/attendance-state.model';\r\nimport { GroupRow } from '../models/group-row.model';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\n\r\n/**\r\n * Mock upcoming-events + groups fixtures for the dashboard library.\r\n *\r\n * These exercise the key presentation edge cases:\r\n * - empty/undefined `groupOrCommittee` and `roomOrLocation` (empty-field placeholder)\r\n * - a mix of `CURRENTLY_ATTENDING` / `NOT_ATTENDING` attendance states\r\n * - events with many meetings so per-card pagination is exercised\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardUpcomingEventsMock: UpcomingEvent[] = [\r\n {\r\n eventId: 'EVT-001',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'NESC Revision Cycle Kickoff',\r\n status: 'In Progress',\r\n dayIndicator: 'Day 1 of 3',\r\n meetingCount: 6,\r\n openForAttendanceCount: 3,\r\n startDate: '2025-03-14T09:00:00',\r\n endDate: '2025-03-16T17:00:00',\r\n timezone: 'America/New_York',\r\n meetings: [\r\n {\r\n meetingId: 'MTG-001',\r\n meetingName: 'Opening Plenary',\r\n groupOrCommittee: 'NESC Main Committee',\r\n roomOrLocation: 'Grand Ballroom A',\r\n meetingDate: '2025-03-14T09:00:00',\r\n meetingTime: '2025-03-14T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-002',\r\n meetingName: 'Subcommittee 1 Working Session',\r\n groupOrCommittee: 'Subcommittee 1 - Grounding',\r\n // RoomOrLocation intentionally omitted to exercise the empty-field placeholder.\r\n meetingDate: '2025-03-14T11:00:00',\r\n meetingTime: '2025-03-14T11:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-003',\r\n meetingName: 'Subcommittee 2 Working Session',\r\n // GroupOrCommittee intentionally empty to exercise the empty-field placeholder.\r\n groupOrCommittee: '',\r\n roomOrLocation: 'Room 204',\r\n meetingDate: '2025-03-14T13:30:00',\r\n meetingTime: '2025-03-14T13:30:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-004',\r\n meetingName: 'Editorial Review',\r\n groupOrCommittee: 'Editorial Task Force',\r\n roomOrLocation: 'Room 118',\r\n meetingDate: '2025-03-15T09:00:00',\r\n meetingTime: '2025-03-15T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-005',\r\n meetingName: 'Interpretations Panel',\r\n groupOrCommittee: 'Interpretations Subcommittee',\r\n roomOrLocation: 'Room 310',\r\n meetingDate: '2025-03-15T14:00:00',\r\n meetingTime: '2025-03-15T14:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-006',\r\n meetingName: 'Closing Plenary',\r\n groupOrCommittee: 'NESC Main Committee',\r\n roomOrLocation: 'Grand Ballroom A',\r\n meetingDate: '2025-03-16T15:00:00',\r\n meetingTime: '2025-03-16T15:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n ],\r\n },\r\n {\r\n eventId: 'EVT-002',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'Standards Board Quarterly Meeting',\r\n status: 'Upcoming',\r\n dayIndicator: 'Day 1 of 1',\r\n meetingCount: 3,\r\n openForAttendanceCount: 1,\r\n startDate: '2025-04-02T08:30:00',\r\n endDate: '2025-04-02T16:00:00',\r\n timezone: 'America/Los_Angeles',\r\n meetings: [\r\n {\r\n meetingId: 'MTG-101',\r\n meetingName: 'Board Opening Remarks',\r\n groupOrCommittee: 'Standards Board',\r\n roomOrLocation: 'Pacific Hall',\r\n meetingDate: '2025-04-02T08:30:00',\r\n meetingTime: '2025-04-02T08:30:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-102',\r\n meetingName: 'Ballot Review Session',\r\n // Both optional location/group fields omitted to exercise placeholders.\r\n meetingDate: '2025-04-02T10:30:00',\r\n meetingTime: '2025-04-02T10:30:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-103',\r\n meetingName: 'Action Items & Wrap-up',\r\n groupOrCommittee: 'Standards Board',\r\n roomOrLocation: 'Pacific Hall',\r\n meetingDate: '2025-04-02T15:00:00',\r\n meetingTime: '2025-04-02T15:00:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n ],\r\n },\r\n {\r\n eventId: 'EVT-003',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'Working Group Interim',\r\n status: 'Upcoming',\r\n // DayIndicator intentionally omitted (optional field).\r\n meetingCount: 0,\r\n openForAttendanceCount: 0,\r\n startDate: '2025-05-20T09:00:00',\r\n endDate: '2025-05-20T12:00:00',\r\n timezone: 'Europe/London',\r\n meetings: [],\r\n },\r\n];\r\n\r\n/**\r\n * Mock a single meeting row with an empty `meetingId` to exercise the\r\n * non-actionable (empty/undefined id) path in the meeting row component.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardNonActionableMeetingMock: MeetingRow = {\r\n meetingId: '',\r\n meetingName: 'Unscheduled Placeholder Session',\r\n groupOrCommittee: '',\r\n meetingDate: '2025-06-01T09:00:00',\r\n meetingTime: '2025-06-01T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n};\r\n\r\n/**\r\n * Mock groups fixtures for the dashboard \"Your Groups\" section.\r\n *\r\n * Includes rows with missing optional fields (`type`, `officerRole`,\r\n * `affiliation`) and a spread of member levels so the member-level badge\r\n * colour map and empty-field placeholders are exercised.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardGroupsMock: GroupRow[] = [\r\n {\r\n groupId: 'GRP-001',\r\n group: 'NESC Main Committee',\r\n type: 'Committee',\r\n officerRole: 'Chair',\r\n affiliation: 'Employer Corp',\r\n memberLevel: 'Senior Member',\r\n },\r\n {\r\n groupId: 'GRP-002',\r\n group: 'Subcommittee 1 - Grounding',\r\n type: 'Subcommittee',\r\n // OfficerRole intentionally omitted (member with no officer role).\r\n affiliation: 'Standards Member',\r\n memberLevel: 'Member',\r\n },\r\n {\r\n groupId: 'GRP-003',\r\n group: 'Editorial Task Force',\r\n // Type and affiliation intentionally omitted to exercise placeholders.\r\n officerRole: 'Secretary',\r\n memberLevel: 'Fellow',\r\n },\r\n {\r\n groupId: 'GRP-004',\r\n group: 'Interpretations Subcommittee',\r\n type: 'Subcommittee',\r\n officerRole: 'Member',\r\n affiliation: 'Tech Solutions Inc',\r\n memberLevel: 'Associate Member',\r\n },\r\n {\r\n groupId: 'GRP-005',\r\n group: 'Standards Board',\r\n type: 'Board',\r\n officerRole: 'Vice Chair',\r\n affiliation: 'CodeCraft Studio',\r\n memberLevel: 'Senior Member',\r\n },\r\n];\r\n","/*\r\n * Public API Surface of dashboard\r\n */\r\n\r\n// Container component + navigation intent type (DashboardComponent, DashboardNavigationIntent)\r\nexport * from './lib/dashboard.component';\r\n\r\n// Child components\r\nexport * from './lib/components/welcome-header/dashboard-welcome-header.component';\r\nexport * from './lib/components/upcoming-meetings-events/upcoming-meetings-events.component';\r\nexport * from './lib/components/event-group-card/event-group-card.component';\r\nexport * from './lib/components/meeting-attendance-row/meeting-attendance-row.component';\r\nexport * from './lib/components/your-groups/your-groups.component';\r\nexport * from './lib/components/member-level-badge/member-level-badge.component';\r\n\r\n// Module + routes\r\nexport * from './lib/dashboard.module';\r\nexport * from './lib/dashboard.routes';\r\n\r\n// Models\r\nexport * from './lib/models/dashboard-route-config.model';\r\nexport * from './lib/models/attendance-state.model';\r\nexport * from './lib/models/dashboard-section-state.model';\r\nexport * from './lib/models/page-change.model';\r\nexport * from './lib/models/dashboard-user-info.model';\r\nexport * from './lib/models/meeting-row.model';\r\nexport * from './lib/models/upcoming-event.model';\r\nexport * from './lib/models/event-meeting-list-item.model';\r\nexport * from './lib/models/event-meeting-list-payload.model';\r\nexport * from './lib/models/group-row.model';\r\nexport * from './lib/models/attendance-action-permissions.model';\r\nexport * from './lib/models/dashboard-list-response.model';\r\n\r\n// Services\r\nexport * from './lib/services/dashboard.service';\r\nexport * from './lib/services/user-permissions.service';\r\n\r\n// Asset mocks consumed by the demo app\r\nexport * from './lib/assets/dashboard-route-paths.mock';\r\nexport * from './lib/assets/dashboard-user-permissions.mock';\r\nexport * from './lib/assets/dashboard-mock';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["screenTexts","constants","i1","i1.DashboardService","i2.UserPermissionsService","i4","i5"],"mappings":";;;;;;;;;;;;;;AAAA;IACY,sBAKX;AALD,CAAA,UAAY,qBAAqB,EAAA;AAC/B,IAAA,qBAAA,CAAA,SAAA,CAAA,GAAA,SAAmB,CAAA;AACnB,IAAA,qBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB,CAAA;AACjB,IAAA,qBAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,qBAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACjB,CAAC,EALW,qBAAqB,KAArB,qBAAqB,GAKhC,EAAA,CAAA,CAAA;;ACND;IACY,gBAGX;AAHD,CAAA,UAAY,eAAe,EAAA;AACzB,IAAA,eAAA,CAAA,qBAAA,CAAA,GAAA,qBAA2C,CAAA;AAC3C,IAAA,eAAA,CAAA,eAAA,CAAA,GAAA,eAA+B,CAAA;AACjC,CAAC,EAHW,eAAe,KAAf,eAAe,GAG1B,EAAA,CAAA,CAAA;;ACFD;AACA;;;;;AAKG;IACS,iBAGX;AAHD,CAAA,UAAY,gBAAgB,EAAA;AAC1B,IAAA,gBAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,gBAAA,CAAA,oBAAA,CAAA,GAAA,oBAAyC,CAAA;AAC3C,CAAC,EAHW,gBAAgB,KAAhB,gBAAgB,GAG3B,EAAA,CAAA,CAAA;;ACZD;;;;;;;;AAQG;AACI,MAAM,WAAW,GAAG;;AAEzB,IAAA,oBAAoB,EAAE,YAAY;;AAElC,IAAA,4BAA4B,EAAE,uBAAuB;;AAErD,IAAA,aAAa,EAAE,aAAa;;AAE5B,IAAA,iBAAiB,EAAE,cAAc;;AAEjC,IAAA,UAAU,EAAE,OAAO;;AAEnB,IAAA,kBAAkB,EAAE,QAAQ;;AAE5B,IAAA,cAAc,EAAE,MAAM;;AAEtB,IAAA,kBAAkB,EAAE,OAAO;CAC5B;;AC1BD;;;;;;;;;AASG;AAGH;AACA;;;;AAIG;AACH,IAAY,gBAIX,CAAA;AAJD,CAAA,UAAY,gBAAgB,EAAA;AAC1B,IAAA,gBAAA,CAAA,gBAAA,CAAA,GAAA,gBAAiC,CAAA;AACjC,IAAA,gBAAA,CAAA,eAAA,CAAA,GAAA,eAA+B,CAAA;AAC/B,IAAA,gBAAA,CAAA,MAAA,CAAA,GAAA,MAAa,CAAA;AACf,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,GAI3B,EAAA,CAAA,CAAA,CAAA;AACD;AAEA;;;;;;;;;;;;;;;AAeG;SACa,uBAAuB,CACrC,eAA4C,EAC5C,UAAmB,EACnB,SAA6B,EAAA;IAE7B,IAAI,CAAC,SAAS,EAAE;QACd,OAAO,gBAAgB,CAAC,IAAI,CAAC;AAC9B,KAAA;AAED,IAAA,IAAI,UAAU,EAAE;QACd,OAAO,gBAAgB,CAAC,IAAI,CAAC;AAC9B,KAAA;AAED,IAAA,IAAI,eAAe,KAAK,eAAe,CAAC,mBAAmB,EAAE;QAC3D,OAAO,gBAAgB,CAAC,aAAa,CAAC;AACvC,KAAA;IAED,OAAO,gBAAgB,CAAC,cAAc,CAAC;AACzC;;AC3DA;;;;;;;;;;AAUG;AAGH;;;;;;AAMG;AACG,SAAU,eAAe,CAC7B,QAA4B,EAAA;IAE5B,IAAI,CAAC,QAAQ,EAAE;AACb,QAAA,OAAO,SAAS,CAAC;AAClB,KAAA;;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC5C,IAAA,MAAM,IAAI,GACR,YAAY,GAAG,CAAC,CAAC;UACb,QAAQ,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;AACzC,UAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;AACtB,IAAA,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAC5C,CAAC;AAED;;;;;;;;;AASG;AACa,SAAA,oBAAoB,CAClC,KAAyC,EACzC,QAAiB,EAAA;AAEjB,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE;AACzD,QAAA,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAClC,KAAA;AACD,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,QAAA,OAAO,IAAI;cACP,QAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC;AACtC,cAAE,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAChC,KAAA;;AAED,IAAA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACnD,IAAA,OAAO,MAAM,CAAC,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;AAQG;SACa,qBAAqB,CACnC,KAAyC,EACzC,MAAc,EACd,QAAiB,EAAA;IAEjB,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACrD,IAAA,OAAO,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;AAOG;SACa,WAAW,CACzB,KAAyC,EACzC,MAAc,EACd,QAAiB,EAAA;IAEjB,OAAO,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;AAQG;SACa,mBAAmB,CACjC,KAAyC,EACzC,GAAuC,EACvC,QAAiB,EAAA;AAEjB,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;AACtC,QAAA,OAAO,EAAE,CAAC;AACX,KAAA;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACpC,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;;IAGrE,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC,IAAA,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS,GAAG,sBAAsB,EAAE;AACxD,QAAA,OAAO,EAAE,CAAC;AACX,KAAA;AACD,IAAA,MAAM,GAAG,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,OAAO,CACxE,KAAK,CACN,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,GAAG,QAAQ,GAAG,QAAQ,GAAG,GAAG,GAAG,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;AAC3E,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1E,IAAA,OAAO,CAAO,IAAA,EAAA,UAAU,CAAO,IAAA,EAAA,SAAS,EAAE,CAAC;AAC7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClHA;;;;;;;;;;;;;AAaG;MAUU,6BAA6B,CAAA;AAT1C,IAAA,WAAA,GAAA;;QAWE,IAAS,CAAA,SAAA,GAAQA,WAAW,CAAC;;AAMpB,QAAA,IAAA,CAAA,eAAe,GAAoB,eAAe,CAAC,aAAa,CAAC;;QAGjE,IAAU,CAAA,UAAA,GAAG,KAAK,CAAC;;AAGnB,QAAA,IAAA,CAAA,WAAW,GAAgC;AAClD,YAAA,gBAAgB,EAAE,KAAK;AACvB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAC;AAEF;;;;AAIG;QACM,IAAO,CAAA,OAAA,GAAG,KAAK,CAAC;;AAGf,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;;AAGzC,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAU,CAAC;;AAG3C,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,YAAY,EAAU,CAAC;;QAG3C,IAAe,CAAA,eAAA,GAAG,eAAe,CAAC;AA0I5C,KAAA;AAxIC;;;;;AAKG;AACH,IAAA,IAAI,YAAY,GAAA;AACd,QAAA,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC;KAClC;AAED;;;;;AAKG;AACH,IAAA,IAAI,oBAAoB,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,eAAe,KAAK,eAAe,CAAC,mBAAmB,CAAC;KACrE;AAED;;;;;;AAMG;AACH,IAAA,IAAI,uBAAuB,GAAA;AACzB,QAAA,OAAO,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC;KAC3E;AAED;;;;;;AAMG;AACH,IAAA,IAAI,sBAAsB,GAAA;QACxB,OAAO,IAAI,CAAC,oBAAoB,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;KACzE;AAED;;;;;;;AAOG;AACH,IAAA,iBAAiB,CAAC,KAAyB,EAAA;QACzC,MAAM,WAAW,GACf,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,qBAAqB,IAAI,GAAG,CAAC;AAC3D,QAAA,OAAO,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,WAAW,CAAC;KAC/D;AAED;;;;;AAKG;AACH,IAAA,IAAI,aAAa,GAAA;AACf,QAAA,MAAM,KAAK,GACT,IAAI,CAAC,OAAO,EAAE,aAAa,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC;AAC3D,QAAA,OAAO,WAAW,CAChB,KAAK,EACL,WAAW,CAAC,aAAa,EACzB,IAAI,CAAC,OAAO,EAAE,QAAQ,CACvB,CAAC;KACH;AAED;;;;;;AAMG;AACH,IAAA,IAAI,aAAa,GAAA;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;AAC9C,QAAA,MAAM,UAAU,GACd,IAAI,CAAC,OAAO,EAAE,aAAa,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC;AAC3D,QAAA,MAAM,KAAK,GAAG,WAAW,CACvB,UAAU,EACV,WAAW,CAAC,kBAAkB,EAC9B,QAAQ,CACT,CAAC;AACF,QAAA,MAAM,GAAG,GAAG,WAAW,CACrB,IAAI,CAAC,OAAO,EAAE,WAAW,EACzB,WAAW,CAAC,kBAAkB,EAC9B,QAAQ,CACT,CAAC;AACF,QAAA,MAAM,KAAK,GAAG,GAAG,GAAG,CAAA,EAAG,KAAK,CAAA,GAAA,EAAM,GAAG,CAAE,CAAA,GAAG,KAAK,CAAC;QAChD,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;AACD,QAAA,OAAO,QAAQ,GAAG,CAAG,EAAA,KAAK,CAAI,CAAA,EAAA,QAAQ,CAAE,CAAA,GAAG,KAAK,CAAC;KAClD;AAED;;;;;;;AAOG;IACH,kBAAkB,GAAA;AAChB,QAAA,MAAM,MAAM,GAAG,uBAAuB,CACpC,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,OAAO,EAAE,SAAS,CACxB,CAAC;AAEF,QAAA,IAAI,MAAM,KAAK,gBAAgB,CAAC,cAAc,EAAE;YAC9C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChD,OAAO;AACR,SAAA;AAED,QAAA,IAAI,MAAM,KAAK,gBAAgB,CAAC,aAAa,EAAE;YAC7C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAChD,SAAA;KACF;AAED;;;;AAIG;IACH,aAAa,GAAA;AACX,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YACtB,OAAO;AACR,SAAA;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;KAC/C;+GA7KU,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;mGAA7B,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,+BAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,YAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,aAAA,EAAA,eAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC1C1C,8uGAiFA,EAAA,MAAA,EAAA,CAAA,qxWAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED5CY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAKX,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBATzC,SAAS;+BAEE,+BAA+B,EAAA,UAAA,EAC7B,IAAI,EACP,OAAA,EAAA,CAAC,YAAY,CAAC,EAAA,aAAA,EAGR,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,8uGAAA,EAAA,MAAA,EAAA,CAAA,qxWAAA,CAAA,EAAA,CAAA;8BAO5B,OAAO,EAAA,CAAA;sBAAf,KAAK;gBAGG,eAAe,EAAA,CAAA;sBAAvB,KAAK;gBAGG,UAAU,EAAA,CAAA;sBAAlB,KAAK;gBAGG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBAUG,OAAO,EAAA,CAAA;sBAAf,KAAK;gBAGI,WAAW,EAAA,CAAA;sBAApB,MAAM;gBAGG,aAAa,EAAA,CAAA;sBAAtB,MAAM;gBAGG,YAAY,EAAA,CAAA;sBAArB,MAAM;;;AElDT;;;;;;;;;;;;;;AAcG;MAUU,uBAAuB,CAAA;AATpC,IAAA,WAAA,GAAA;;;QAYE,IAAS,CAAA,SAAA,GAAQA,WAAW,CAAC;;QAGpB,IAAS,CAAA,SAAA,GAAG,gBAAgB,CAAC;;AAoB7B,QAAA,IAAA,CAAA,WAAW,GAAgC;AAClD,YAAA,gBAAgB,EAAE,KAAK;AACvB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAC;;QAGO,IAAgB,CAAA,gBAAA,GAAoC,EAAE,CAAC;;AAGvD,QAAA,IAAA,CAAA,kBAAkB,GAAwB,IAAI,GAAG,EAAU,CAAC;;QAG5D,IAAY,CAAA,YAAA,GAAG,KAAK,CAAC;;AAGpB,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,YAAY,EAAU,CAAC;;AAGvC,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;;AAGzC,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAU,CAAC;;AAG3C,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,YAAY,EAAU,CAAC;;AAG1C,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,YAAY,EAAc,CAAC;AAEtD;;;;AAIG;AACO,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,YAAY,EAAU,CAAC;;QAG3C,IAAe,CAAA,eAAA,GAAG,CAAC,CAAC;;QAG7B,IAAS,CAAA,SAAA,GAAG,CAAC,CAAC;;AAGd,QAAA,IAAA,CAAA,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC;;QAGhC,IAAiB,CAAA,iBAAA,GAAG,KAAK,CAAC;AA8V3B,KAAA;AA9ZC;;;;;;AAMG;AACH,IAAA,IAAI,cAAc,GAAA;QAChB,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE;AAC7B,aAAA,IAAI,EAAE;AACN,aAAA,WAAW,EAAE;AACb,aAAA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACzB;AAsDD;;;;;AAKG;AACH,IAAA,IAAI,YAAY,GAAA;QACd,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,gBAAgB,CAAC,kBAAkB,CAAC;KACjE;AAED;;;;;AAKG;AACH,IAAA,IAAI,QAAQ,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,CAAC;KACnC;AAED;;;;;;AAMG;AACH,IAAA,IAAI,aAAa,GAAA;QACf,OAAO,IAAI,CAAC,KAAK,EAAE,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;KACzD;AAED;;;;;;AAMG;AACH,IAAA,IAAI,aAAa,GAAA;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC;KACtB;AAED;;;;;AAKG;AACH,IAAA,IAAI,UAAU,GAAA;QACZ,OAAO,IAAI,CAAC,aAAa,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;KAC1E;AAED;;;;;AAKG;AACH,IAAA,IAAI,QAAQ,GAAA;QACV,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;KAC3E;AAED;;;;;AAKG;AACH,IAAA,IAAI,UAAU,GAAA;QACZ,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa;AACxD,YAAA,kCAAkC,CAAC;AACrC,QAAA,OAAO,QAAQ;aACZ,OAAO,CAAC,SAAS,EAAE,CAAA,EAAG,IAAI,CAAC,UAAU,EAAE,CAAC;aACxC,OAAO,CAAC,OAAO,EAAE,CAAA,EAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;aACpC,OAAO,CAAC,SAAS,EAAE,CAAA,EAAG,IAAI,CAAC,aAAa,CAAE,CAAA,CAAC,CAAC;KAChD;AAED;;;;;AAKG;AACH,IAAA,IAAI,mBAAmB,GAAA;QACrB,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa;AACxD,YAAA,kBAAkB,CAAC;AACrB,QAAA,OAAO,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,CAAG,EAAA,IAAI,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAA,CAAE,CAAC,CAAC;KACxE;AAED;;;;;;;AAOG;AACH,IAAA,IAAI,YAAY,GAAA;QACd,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,gBAAgB,IAAI,EAAE,CAAC;YACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,cAAc,IAAI,EAAE,CAAC;YAClD,IAAI,KAAK,IAAI,QAAQ,EAAE;AACrB,gBAAA,OAAO,CAAG,EAAA,KAAK,CAAW,QAAA,EAAA,QAAQ,EAAE,CAAC;AACtC,aAAA;YACD,OAAO,KAAK,IAAI,QAAQ,CAAC;AAC1B,SAAA;QACD,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAC;KAC5E;AAED;;;;;;;AAOG;AACH,IAAA,IAAI,sBAAsB,GAAA;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAC;QACjE,IAAI,IAAI,CAAC,iBAAiB,EAAE;AAC1B,YAAA,OAAO,MAAM,EAAE,SAAS,IAAI,eAAe,CAAC;AAC7C,SAAA;AACD,QAAA,OAAO,MAAM,EAAE,SAAS,IAAI,eAAe,CAAC;KAC7C;AAED;;;;;;AAMG;AACH,IAAA,IAAI,wBAAwB,GAAA;QAC1B,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,yBAAyB;AACzD,YAAA,sCAAsC,CAAC;AACzC,QAAA,OAAO,QAAQ,CAAC,OAAO,CACrB,SAAS,EACT,CAAG,EAAA,IAAI,CAAC,KAAK,EAAE,sBAAsB,IAAI,CAAC,CAAA,CAAE,CAC7C,CAAC;KACH;AAED;;;;;;AAMG;AACH,IAAA,IAAI,iBAAiB,GAAA;QACnB,OAAO;AACL,YAAA,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE;AACpC,YAAA,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;AACpC,YAAA,gBAAgB,EAAE,IAAI,CAAC,KAAK,EAAE,gBAAgB;AAC9C,YAAA,cAAc,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc;YAC1C,aAAa,EAAE,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS;YACjE,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO;AAC3D,YAAA,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE;AACpC,YAAA,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM;AAC1B,YAAA,eAAe,EAAE,IAAI,CAAC,KAAK,EAAE,eAAe;SAC7C,CAAC;KACH;AAED;;;;;AAKG;AACH,IAAA,IAAI,cAAc,GAAA;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,WAAW,CACvB,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS,EAClD,WAAW,CAAC,kBAAkB,EAC9B,QAAQ,CACT,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CACrB,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAC9C,WAAW,CAAC,kBAAkB,EAC9B,QAAQ,CACT,CAAC;AACF,QAAA,MAAM,KAAK,GAAG,GAAG,GAAG,CAAA,EAAG,KAAK,CAAA,QAAA,EAAW,GAAG,CAAE,CAAA,GAAG,KAAK,CAAC;QACrD,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;AACD,QAAA,OAAO,QAAQ,GAAG,CAAG,EAAA,KAAK,CAAI,CAAA,EAAA,QAAQ,CAAE,CAAA,GAAG,KAAK,CAAC;KAClD;AAED;;;;;AAKG;AACH,IAAA,IAAI,qBAAqB,GAAA;QACvB,QACE,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,iBAAiB,CAAC;YACnD,eAAe,CAAC,mBAAmB,EACnC;KACH;AAED;;;;;AAKG;AACH,IAAA,IAAI,iBAAiB,GAAA;AACnB,QAAA,OAAO,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC;KAC5E;AAED;;;;;AAKG;AACH,IAAA,IAAI,mBAAmB,GAAA;QACrB,OAAO,IAAI,CAAC,qBAAqB,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;KAC1E;;AAGD,IAAA,IAAI,kBAAkB,GAAA;AACpB,QAAA,OAAO,IAAI,CAAC,UAAU,CACpB,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS,CACnD,CAAC;KACH;;AAGD,IAAA,IAAI,gBAAgB,GAAA;AAClB,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;KACxE;AAED;;;;;;;AAOG;IACH,gBAAgB,CAAC,MAAc,EAAE,OAAmB,EAAA;AAClD,QAAA,OAAO,OAAO,EAAE,SAAS,IAAI,CAAG,EAAA,MAAM,EAAE,CAAC;KAC1C;AAED;;;;;;AAMG;AACH,IAAA,sBAAsB,CAAC,OAAmB,EAAA;QACxC,QACE,IAAI,CAAC,gBAAgB,GAAG,OAAO,EAAE,SAAS,CAAC;YAC3C,eAAe,CAAC,aAAa,EAC7B;KACH;AAED;;;;;;AAMG;AACH,IAAA,iBAAiB,CAAC,OAAmB,EAAA;AACnC,QAAA,OAAO,IAAI,CAAC,kBAAkB,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,KAAK,CAAC;KAClE;AAED;;;;AAIG;IACH,mBAAmB,GAAA;AACjB,QAAA,IAAI,CAAC,iBAAiB,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC;QACjD,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAC5C,SAAA;KACF;AAED;;;AAGG;IACH,WAAW,GAAA;QACT,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;KAC1C;AAED;;;;AAIG;AACH,IAAA,aAAa,CAAC,SAAiB,EAAA;AAC7B,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KAClC;AAED;;;;AAIG;AACH,IAAA,eAAe,CAAC,SAAiB,EAAA;AAC/B,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KACpC;AAED;;;;AAIG;AACH,IAAA,cAAc,CAAC,SAAiB,EAAA;AAC9B,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KACnC;AAED;;;;;AAKG;AACH,IAAA,YAAY,CAAC,KAAgB,EAAA;AAC3B,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;AACjC,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;AAC/B,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACzB,SAAA,CAAC,CAAC;;QAEH,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;KAC7C;AAED;;;;;;;;AAQG;AACK,IAAA,UAAU,CAAC,KAAyC,EAAA;AAC1D,QAAA,OAAO,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;KAC5E;+GAraU,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,gbCjDpC,okRA2NA,EAAA,MAAA,EAAA,CAAA,qydAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED/KY,YAAY,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,kBAAkB,0JAAE,6BAA6B,EAAA,QAAA,EAAA,+BAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,aAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,eAAA,EAAA,cAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAK9D,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBATnC,SAAS;AAEE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,EACvB,UAAA,EAAA,IAAI,EACP,OAAA,EAAA,CAAC,YAAY,EAAE,kBAAkB,EAAE,6BAA6B,CAAC,EAG3D,aAAA,EAAA,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,okRAAA,EAAA,MAAA,EAAA,CAAA,qydAAA,CAAA,EAAA,CAAA;8BAyB5B,KAAK,EAAA,CAAA;sBAAb,KAAK;gBAGG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBAMG,gBAAgB,EAAA,CAAA;sBAAxB,KAAK;gBAGG,kBAAkB,EAAA,CAAA;sBAA1B,KAAK;gBAGG,YAAY,EAAA,CAAA;sBAApB,KAAK;gBAGI,SAAS,EAAA,CAAA;sBAAlB,MAAM;gBAGG,WAAW,EAAA,CAAA;sBAApB,MAAM;gBAGG,aAAa,EAAA,CAAA;sBAAtB,MAAM;gBAGG,YAAY,EAAA,CAAA;sBAArB,MAAM;gBAGG,UAAU,EAAA,CAAA;sBAAnB,MAAM;gBAOG,YAAY,EAAA,CAAA;sBAArB,MAAM;;;AExFT;;;;;;;;;;;;;;;;;;AAkBG;MAeU,+BAA+B,CAAA;AAd5C,IAAA,WAAA,GAAA;;;QAiBE,IAAS,CAAA,SAAA,GAAQA,WAAW,CAAC;;QAGpB,IAAa,CAAA,aAAA,GAAG,qBAAqB,CAAC;;QAGtC,IAAM,CAAA,MAAA,GAAoB,EAAE,CAAC;;AAG7B,QAAA,IAAA,CAAA,YAAY,GAA0B,qBAAqB,CAAC,OAAO,CAAC;;AAGpE,QAAA,IAAA,CAAA,WAAW,GAAgC;AAClD,YAAA,gBAAgB,EAAE,KAAK;AACvB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAC;;QAGO,IAAgB,CAAA,gBAAA,GAAoC,EAAE,CAAC;;AAGvD,QAAA,IAAA,CAAA,kBAAkB,GAAwB,IAAI,GAAG,EAAU,CAAC;;QAG5D,IAAY,CAAA,YAAA,GAAG,KAAK,CAAC;;AAGpB,QAAA,IAAA,CAAA,OAAO,GAAG,IAAI,YAAY,EAAQ,CAAC;;AAGnC,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,YAAY,EAAU,CAAC;;AAGvC,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;;AAGzC,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAU,CAAC;;AAG3C,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,YAAY,EAAU,CAAC;;AAG1C,QAAA,IAAA,CAAA,iBAAiB,GAAG,IAAI,YAAY,EAAoC,CAAC;;AAGzE,QAAA,IAAA,CAAA,iBAAiB,GAAG,IAAI,YAAY,EAAqC,CAAC;;QAGpF,IAAU,CAAA,UAAA,GAAG,KAAK,CAAC;;QAGV,IAAe,CAAA,eAAA,GAAG,CAAC,CAAC;;QAG7B,IAAgB,CAAA,gBAAA,GAAG,CAAC,CAAC;AAyErB;;;;;;AAMG;AACO,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,YAAY,EAAW,CAAC;AAyFxD,KAAA;;AAtKC,IAAA,IAAI,UAAU,GAAA;AACZ,QAAA,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;KACjC;AAED;;;;;AAKG;AACH,IAAA,IAAI,WAAW,GAAA;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,eAAe,CAAC;AAC3D,QAAA,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;KACvE;;AAGD,IAAA,IAAI,iBAAiB,GAAA;AACnB,QAAA,OAAO,IAAI,CAAC,UAAU,KAAK,CAAC;AAC1B,cAAE,CAAC;cACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;KACtD;;AAGD,IAAA,IAAI,eAAe,GAAA;QACjB,OAAO,IAAI,CAAC,GAAG,CACb,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAI,IAAI,CAAC,eAAe,EAClD,IAAI,CAAC,UAAU,CAChB,CAAC;KACH;AAED;;;;;AAKG;AACH,IAAA,IAAI,iBAAiB,GAAA;QACnB,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa;AACzD,YAAA,4CAA4C,CAAC;AAC/C,QAAA,OAAO,QAAQ;aACZ,OAAO,CAAC,SAAS,EAAE,CAAA,EAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;aAC/C,OAAO,CAAC,OAAO,EAAE,CAAA,EAAG,IAAI,CAAC,eAAe,EAAE,CAAC;aAC3C,OAAO,CAAC,SAAS,EAAE,CAAA,EAAG,IAAI,CAAC,UAAU,CAAE,CAAA,CAAC,CAAC;KAC7C;AAED;;;;;AAKG;AACH,IAAA,mBAAmB,CAAC,KAAgB,EAAA;AAClC,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,SAAS,CAAC;KACzC;AAED;;;;;AAKG;IACH,IACI,QAAQ,CAAC,KAAc,EAAA;AACzB,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC;KAC3B;AACD,IAAA,IAAI,QAAQ,GAAA;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;KACxB;AAWD;;;;;;;AAOG;IACH,cAAc,CAAC,KAAa,EAAE,KAAoB,EAAA;AAChD,QAAA,OAAO,KAAK,EAAE,OAAO,IAAI,CAAG,EAAA,KAAK,EAAE,CAAC;KACrC;AAED;;;;AAIG;IACH,gBAAgB,GAAA;AACd,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KAC3C;AAED;;;AAGG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;KACrB;AAED;;;;AAIG;AACH,IAAA,WAAW,CAAC,OAAe,EAAA;AACzB,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC9B;AAED;;;;AAIG;AACH,IAAA,aAAa,CAAC,SAAiB,EAAA;AAC7B,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KAClC;AAED;;;;AAIG;AACH,IAAA,eAAe,CAAC,SAAiB,EAAA;AAC/B,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KACpC;AAED;;;;AAIG;AACH,IAAA,cAAc,CAAC,SAAiB,EAAA;AAC9B,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KACnC;AAED;;;;;;AAMG;IACH,mBAAmB,CAAC,OAAe,EAAE,IAAgB,EAAA;AACnD,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;KACnD;AAED;;;;;;AAMG;IACH,mBAAmB,CAAC,OAAe,EAAE,IAAY,EAAA;QAC/C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;KAChD;+GAjOU,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;mGAA/B,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,YAAA,EAAA,cAAA,EAAA,WAAA,EAAA,aAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,SAAA,EAAA,WAAA,EAAA,WAAA,EAAA,aAAA,EAAA,aAAA,EAAA,eAAA,EAAA,YAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECtD5C,ojIA2GA,ED9DI,MAAA,EAAA,CAAA,srVAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,YAAY,6VACZ,kBAAkB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,eAAe,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACf,uBAAuB,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,cAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,aAAA,EAAA,eAAA,EAAA,cAAA,EAAA,YAAA,EAAA,cAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAMd,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAd3C,SAAS;+BAEE,iCAAiC,EAAA,UAAA,EAC/B,IAAI,EACP,OAAA,EAAA;wBACP,YAAY;wBACZ,kBAAkB;wBAClB,eAAe;wBACf,uBAAuB;qBACxB,EAGc,aAAA,EAAA,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,ojIAAA,EAAA,MAAA,EAAA,CAAA,srVAAA,CAAA,EAAA,CAAA;8BAW5B,MAAM,EAAA,CAAA;sBAAd,KAAK;gBAGG,YAAY,EAAA,CAAA;sBAApB,KAAK;gBAGG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBAMG,gBAAgB,EAAA,CAAA;sBAAxB,KAAK;gBAGG,kBAAkB,EAAA,CAAA;sBAA1B,KAAK;gBAGG,YAAY,EAAA,CAAA;sBAApB,KAAK;gBAGI,OAAO,EAAA,CAAA;sBAAhB,MAAM;gBAGG,SAAS,EAAA,CAAA;sBAAlB,MAAM;gBAGG,WAAW,EAAA,CAAA;sBAApB,MAAM;gBAGG,aAAa,EAAA,CAAA;sBAAtB,MAAM;gBAGG,YAAY,EAAA,CAAA;sBAArB,MAAM;gBAGG,iBAAiB,EAAA,CAAA;sBAA1B,MAAM;gBAGG,iBAAiB,EAAA,CAAA;sBAA1B,MAAM;gBA2EH,QAAQ,EAAA,CAAA;sBADX,KAAK;gBAeI,cAAc,EAAA,CAAA;sBAAvB,MAAM;;;AErLT;;;;AAIG;AACH;IACY,oBAKX;AALD,CAAA,UAAY,mBAAmB,EAAA;;AAE7B,IAAA,mBAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;;AAErB,IAAA,mBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB,CAAA;AACnB,CAAC,EALW,mBAAmB,KAAnB,mBAAmB,GAK9B,EAAA,CAAA,CAAA,CAAA;AAeD;;;;;;;;;;;;;;AAcG;MAUU,+BAA+B,CAAA;AAT5C,IAAA,WAAA,GAAA;;QAWmB,IAAS,CAAA,SAAA,GAAQC,WAAS,CAAC;;AAEnC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC;;QAGtC,IAAU,CAAA,UAAA,GAAG,mBAAmB,CAAC;QAElC,IAAa,CAAA,aAAA,GAAG,EAAE,CAAC;QAcnB,IAAkB,CAAA,kBAAA,GAAG,CAAC,CAAC;QAWvB,IAAgB,CAAA,gBAAA,GAAG,CAAC,CAAC;;AAYnB,QAAA,IAAA,CAAA,gBAAgB,GAAG,IAAI,YAAY,EAAuB,CAAC;;AAGrE,QAAA,IAAA,CAAA,SAAS,GAAmB,IAAI,CAAC,iBAAiB,EAAE,CAAC;AAiEtD,KAAA;AAxGC;;;;AAIG;IACH,IACI,QAAQ,CAAC,KAAa,EAAA;AACxB,QAAA,IAAI,CAAC,aAAa,GAAG,KAAK,IAAI,EAAE,CAAC;KAClC;AACD,IAAA,IAAI,QAAQ,GAAA;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;KAC3B;;IAID,IACI,aAAa,CAAC,KAAa,EAAA;AAC7B,QAAA,IAAI,CAAC,kBAAkB,GAAG,KAAK,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,cAAc,EAAE,CAAC;KACvB;AACD,IAAA,IAAI,aAAa,GAAA;QACf,OAAO,IAAI,CAAC,kBAAkB,CAAC;KAChC;;IAID,IACI,WAAW,CAAC,KAAa,EAAA;AAC3B,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,cAAc,EAAE,CAAC;KACvB;AACD,IAAA,IAAI,WAAW,GAAA;QACb,OAAO,IAAI,CAAC,gBAAgB,CAAC;KAC9B;AAQD;;;;;AAKG;AACH,IAAA,IAAI,QAAQ,GAAA;QACV,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACnC,QAAA,OAAO,IAAI;cACP,GAAG,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAG,EAAA,IAAI,CAAG,CAAA,CAAA;cACjC,GAAG,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,CAAC;KACxC;AAED;;;;AAIG;AACH,IAAA,eAAe,CAAC,MAA2B,EAAA;AACzC,QAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;KACpC;AAED;;;;;;AAMG;IACH,aAAa,CAAC,MAAc,EAAE,QAAsB,EAAA;QAClD,OAAO,QAAQ,CAAC,MAAM,CAAC;KACxB;;IAGO,cAAc,GAAA;AACpB,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;KAC3C;AAED;;;;;AAKG;IACK,iBAAiB,GAAA;QACvB,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,CAAC;QAC/D,OAAO;AACL,YAAA;gBACE,MAAM,EAAE,mBAAmB,CAAC,QAAQ;AACpC,gBAAA,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK;AACrC,gBAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO;AACzC,gBAAA,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS;gBAC7C,KAAK,EAAE,IAAI,CAAC,kBAAkB;AAC/B,aAAA;AACD,YAAA;gBACE,MAAM,EAAE,mBAAmB,CAAC,MAAM;AAClC,gBAAA,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK;AACnC,gBAAA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO;AACvC,gBAAA,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS;gBAC3C,KAAK,EAAE,IAAI,CAAC,gBAAgB;AAC7B,aAAA;SACF,CAAC;KACH;+GAjHU,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;mGAA/B,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA,aAAA,EAAA,eAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,OAAA,EAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5D5C,m9CAwCA,EAAA,MAAA,EAAA,CAAA,k0XAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDeY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAKX,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAT3C,SAAS;+BAEE,iCAAiC,EAAA,UAAA,EAC/B,IAAI,EACP,OAAA,EAAA,CAAC,YAAY,CAAC,EAAA,aAAA,EAGR,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,m9CAAA,EAAA,MAAA,EAAA,CAAA,k0XAAA,CAAA,EAAA,CAAA;8BAkBjC,QAAQ,EAAA,CAAA;sBADX,KAAK;gBAWF,aAAa,EAAA,CAAA;sBADhB,KAAK;gBAYF,WAAW,EAAA,CAAA;sBADd,KAAK;gBAUI,gBAAgB,EAAA,CAAA;sBAAzB,MAAM;;;AEnET;;;;;;;;;;;;;;;AAeG;MAeU,mBAAmB,CAAA;AAdhC,IAAA,WAAA,GAAA;;QAgBmB,IAAS,CAAA,SAAA,GAAQA,WAAS,CAAC;;AAEnC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC;;QAGtC,IAAa,CAAA,aAAA,GAAG,qBAAqB,CAAC;;QAGtC,IAAc,CAAA,cAAA,GAAG,EAAE,CAAC;;QAGpB,IAAe,CAAA,eAAA,GAAa,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAEjD;;;;AAIG;AACM,QAAA,IAAA,CAAA,gBAAgB,GAAe;AACtC,YAAA,EAAE,EAAE,CAAC;AACL,YAAA,OAAO,EAAE,6DAA6D;AACtE,YAAA,SAAS,EAAE,cAAc;AACzB,YAAA,OAAO,EAAE,cAAc;SACxB,CAAC;;AAGO,QAAA,IAAA,CAAA,kBAAkB,GAAe;AACxC,YAAA,EAAE,EAAE,CAAC;AACL,YAAA,OAAO,EAAE,8DAA8D;AACvE,YAAA,SAAS,EAAE,gBAAgB;AAC3B,YAAA,OAAO,EAAE,gBAAgB;SAC1B,CAAC;QAyBM,IAAW,CAAA,WAAA,GAAe,EAAE,CAAC;;AAY5B,QAAA,IAAA,CAAA,YAAY,GAA0B,qBAAqB,CAAC,MAAM,CAAC;;QAGnE,IAAW,CAAA,WAAA,GAAG,CAAC,CAAC;QAEjB,IAAc,CAAA,cAAA,GAAG,CAAC,CAAC;QAWnB,IAAa,CAAA,aAAA,GAAG,CAAC,CAAC;;AAYhB,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAQ,CAAC;;AAGzC,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,YAAY,EAAc,CAAC;AAEtD;;;;;;;AAOG;AACO,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,YAAY,EAAW,CAAC;;QAGvD,IAAU,CAAA,UAAA,GAAG,KAAK,CAAC;AAenB;;;;;;AAMG;AACc,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;;QAGlD,IAAW,CAAA,WAAA,GAAe,EAAE,CAAC;AAiM9B,KAAA;AAzSC;;;;;;;;AAQG;IACH,eAAe,CAAC,KAAe,EAAE,KAAa,EAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;cAC7C,IAAI,CAAC,kBAAkB;AACzB,cAAE,IAAI,CAAC,gBAAgB,CAAC;;;;AAI1B,QAAA,MAAM,IAAI,GACR,KAAK,GAAG,CAAC;cACL,KAAK,CAAC,KAAK;AACb,cAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC;AACzD,QAAA,OAAO,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAA,EAAG,MAAM,CAAC,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,EAAE,CAAC;KAChE;;IAID,IACI,MAAM,CAAC,KAAiB,EAAA;AAC1B,QAAA,IAAI,CAAC,WAAW,GAAG,KAAK,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,WAAW,EAAE,CAAC;KACpB;AACD,IAAA,IAAI,MAAM,GAAA;QACR,OAAO,IAAI,CAAC,WAAW,CAAC;KACzB;;IAUD,IACI,SAAS,CAAC,KAAa,EAAA;AACzB,QAAA,IAAI,CAAC,cAAc,GAAG,KAAK,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,WAAW,EAAE,CAAC;KACpB;AACD,IAAA,IAAI,SAAS,GAAA;QACX,OAAO,IAAI,CAAC,cAAc,CAAC;KAC5B;;IAID,IACI,QAAQ,CAAC,KAAa,EAAA;AACxB,QAAA,IAAI,CAAC,aAAa,GAAG,KAAK,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,WAAW,EAAE,CAAC;KACpB;AACD,IAAA,IAAI,QAAQ,GAAA;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;KAC3B;AAqBD;;;;AAIG;IACH,IACI,QAAQ,CAAC,KAAc,EAAA;AACzB,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC;KAC3B;AACD,IAAA,IAAI,QAAQ,GAAA;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;KACxB;AAcD;;;;;AAKG;AACH,IAAA,IAAI,UAAU,GAAA;QACZ,OAAO,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;KACpD;AAED;;;;;;;AAOG;IACK,QAAQ,CAAC,KAAe,EAAE,KAAa,EAAA;AAC7C,QAAA,OAAO,GAAG,KAAK,CAAC,OAAO,CAAI,CAAA,EAAA,KAAK,EAAE,CAAC;KACpC;AAED;;;;;;;;;;;;AAYG;IACH,iBAAiB,CAAC,KAAe,EAAE,KAAa,EAAA;QAC9C,MAAM,MAAM,GAAG,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,CAAC;QAC7C,IAAI,KAAK,GAAG,CAAC,EAAE;;;;YAIb,OAAO,MAAM,GAAG,CAAC,CAAC;AACnB,SAAA;;AAED,QAAA,OAAO,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;KAC3B;AAED;;;;;AAKG;AACH,IAAA,YAAY,CAAC,KAAe,EAAA;QAC1B,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;KAC5C;AAED;;;;;;AAMG;IACH,eAAe,CAAC,KAAe,EAAE,KAAa,EAAA;AAC5C,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;KAC3D;;AAGD,IAAA,eAAe,CAAC,KAAe,EAAA;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;KACxC;AAED;;;;;;AAMG;IACH,aAAa,CAAC,KAAe,EAAE,KAAa,EAAA;QAC1C,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;YACzC,OAAO;AACR,SAAA;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;;YAE9B,MAAM,MAAM,GAAG,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,CAAC;YAC7C,KAAK,IAAI,MAAM,GAAG,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,EAAE;AAClD,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AACxD,aAAA;AACF,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5B,SAAA;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;KACpB;AAED;;;;AAIG;IACH,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KAC3C;AAED;;;AAGG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;KAC3B;AAED;;;;;AAKG;AACH,IAAA,iBAAiB,CAAC,KAAgB,EAAA;AAChC,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACzB,SAAA,CAAC,CAAC;KACJ;AAED;;;;;;AAMG;AACH,IAAA,iBAAiB,CAAC,WAAmB,EAAA;AACnC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,gBAAgB,CAAC;AAC3C,QAAA,OAAO,WAAW,KAAK,IAAI,CAAC,KAAK,EAAE,qBAAqB;cACpD,KAAK,EAAE,OAAO;AAChB,cAAE,KAAK,EAAE,OAAO,CAAC;KACpB;AAED;;;;;;AAMG;IACH,UAAU,CAAC,KAAa,EAAE,GAAa,EAAA;AACrC,QAAA,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO;AACzB,cAAE,CAAK,EAAA,EAAA,GAAG,CAAC,KAAK,EAAE,OAAO,CAAE,CAAA;AAC3B,cAAE,CAAK,EAAA,EAAA,GAAG,CAAC,KAAK,EAAE,OAAO,CAAA,CAAA,EAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAI,CAAA,EAAA,KAAK,EAAE,CAAC;KAC7D;AAED;;;;;;;AAOG;IACK,WAAW,GAAA;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;AAC7C,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnE,MAAM,IAAI,GAAe,EAAE,CAAC;AAE5B,QAAA,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;AAC3B,YAAA,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AAE9C,YAAA,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;;;;AAIxC,YAAA,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gBACrD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE;oBAC3C,MAAM;AACP,iBAAA;gBACD,IAAI,CAAC,IAAI,CAAC;AACR,oBAAA,IAAI,EAAE,WAAW;oBACjB,KAAK;AACL,oBAAA,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC;AACtB,oBAAA,SAAS,EAAE,KAAK;oBAChB,KAAK,EAAE,KAAK,GAAG,CAAC;AACjB,iBAAA,CAAC,CAAC;AACJ,aAAA;AACH,SAAC,CAAC,CAAC;AAEH,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;KACzB;+GA3UU,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;mGAAnB,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,YAAA,EAAA,cAAA,EAAA,WAAA,EAAA,aAAA,EAAA,SAAA,EAAA,WAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,UAAA,EAAA,YAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECrEhC,yqNA+JA,EDnGI,MAAA,EAAA,CAAA,08XAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,YAAY,6VACZ,kBAAkB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,eAAe,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACf,mBAAmB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAMV,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAd/B,SAAS;+BAEE,oBAAoB,EAAA,UAAA,EAClB,IAAI,EACP,OAAA,EAAA;wBACP,YAAY;wBACZ,kBAAkB;wBAClB,eAAe;wBACf,mBAAmB;qBACpB,EAGc,aAAA,EAAA,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,yqNAAA,EAAA,MAAA,EAAA,CAAA,08XAAA,CAAA,EAAA,CAAA;8BA+DjC,MAAM,EAAA,CAAA;sBADT,KAAK;gBAUG,YAAY,EAAA,CAAA;sBAApB,KAAK;gBAGG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBAKF,SAAS,EAAA,CAAA;sBADZ,KAAK;gBAYF,QAAQ,EAAA,CAAA;sBADX,KAAK;gBAUI,aAAa,EAAA,CAAA;sBAAtB,MAAM;gBAGG,UAAU,EAAA,CAAA;sBAAnB,MAAM;gBAUG,cAAc,EAAA,CAAA;sBAAvB,MAAM;gBAWH,QAAQ,EAAA,CAAA;sBADX,KAAK;;;AE1KR;;;;;;AAMG;AACG,SAAU,eAAe,CAC7B,IAA0B,EAAA;AAE1B,IAAA,MAAM,OAAO,GAAG,IAAI,EAAE,cAAc,KAAK,IAAI,IAAI,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;AAC5E,IAAA,OAAO,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,gBAAgB,CAAC,kBAAkB,CAAC;AAChF,CAAC;AAED;;;;;;AAMG;AACG,SAAU,0BAA0B,CACxC,IAA0B,EAAA;AAE1B,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;AACnC,IAAA,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;AACtC,IAAA,MAAM,YAAY,GAChB,IAAI,EAAE,YAAY;AAClB,SAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK;AAC9B,cAAE,mBAAmB,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC;cACrE,EAAE,CAAC,CAAC;IACV,OAAO;AACL,QAAA,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,SAAS,IAAI,EAAE;QAC3D,IAAI;;QAEJ,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,YAAY,IAAI,EAAE;;QAE7C,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI,EAAE,gBAAgB,IAAI,EAAE;QACpD,YAAY;AACZ,QAAA,YAAY,EACV,IAAI,KAAK,gBAAgB,CAAC,kBAAkB;AAC1C,cAAE,CAAC;AACH,cAAE,IAAI,EAAE,YAAY,IAAI,CAAC;AAC7B,QAAA,sBAAsB,EAAE,IAAI,EAAE,sBAAsB,IAAI,CAAC;QACzD,aAAa,EAAE,IAAI,EAAE,aAAa;QAClC,WAAW,EAAE,IAAI,EAAE,WAAW;QAC9B,QAAQ;QACR,gBAAgB,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE,YAAY,IAAI,EAAE;QAC7D,cAAc,EAAE,IAAI,EAAE,eAAe,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE;AACzD,QAAA,eAAe,EAAE,IAAI,EAAE,eAAe,IAAI,KAAK;AAC/C,QAAA,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED;;;;;;AAMG;AACG,SAAU,mBAAmB,CACjC,KAA6B,EAAA;IAE7B,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7E,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAC1B,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK,CACjD,CAAC;AACF,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAC9B,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,kBAAkB,CAC9D,CAAC;AACF,IAAA,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC;AACpC,CAAC;AAED;;;;;AAKG;AACG,SAAU,yBAAyB,CACvC,IAA4B,EAAA;AAE5B,IAAA,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC;;;;AAIlC,IAAA,MAAM,mBAAmB,GACvB,IAAI,EAAE,mBAAmB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC;IAC7E,OAAO;AACL,QAAA,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE;AAChC,QAAA,WAAW,EAAE,IAAI,EAAE,YAAY,IAAI,EAAE;AACrC,QAAA,gBAAgB,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE;AACvC,QAAA,cAAc,EAAE,IAAI,EAAE,eAAe,IAAI,EAAE;QAC3C,aAAa,EAAE,IAAI,EAAE,aAAa;QAClC,WAAW,EAAE,IAAI,EAAE,aAAa;AAChC,QAAA,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE;QAC9B,MAAM;AACN,QAAA,eAAe,EAAE,IAAI,EAAE,eAAe,IAAI,KAAK;QAC/C,mBAAmB;KACpB,CAAC;AACJ,CAAC;AAED;;;;;AAKG;AACG,SAAU,sBAAsB,CACpC,KAA+B,EAAA;AAE/B,IAAA,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;AACtE;;ACnIA;;;;AAIG;AAEH;;;;;;;AAOG;AACI,MAAM,yBAAyB,GAAG,CACvC,GAAoC,EACpC,SAAiB,MACoB;AACrC,IAAA,GAAG,GAAG;AACN,IAAA,CAAC,SAAS,GAAG,eAAe,CAAC,mBAAmB;AACjD,CAAA,CAAC,CAAC;AAEH;;;;;;;AAOG;AACI,MAAM,wBAAwB,GAAG,CACtC,GAAoC,EACpC,SAAiB,MACoB;AACrC,IAAA,GAAG,GAAG;AACN,IAAA,CAAC,SAAS,GAAG,eAAe,CAAC,aAAa;AAC3C,CAAA,CAAC,CAAC;AAEH;;;;;;;;AAQG;AACI,MAAM,qBAAqB,GAAG,CACnC,GAAwB,EACxB,SAAiB,KACD,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/C;;;;;;;AAOG;AACI,MAAM,mBAAmB,GAAG,CACjC,GAAwB,EACxB,SAAiB,KACF;AACf,IAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1B,IAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACvB,IAAA,OAAO,IAAI,CAAC;AACd,CAAC;;ACjCD;AACA,MAAM,gBAAgB,GAAG,YAAY,CAAC;AACtC;AACA,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB;AACA,MAAM,iBAAiB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;AACtD;AACA,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAC7C;AACA,MAAM,0BAA0B,GAAG,eAAe,CAAC;AACnD;AACA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B;AACA,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC;AACA,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAQlC;;;;;;;;;;;;;;;;;AAiBG;MAIU,gBAAgB,CAAA;AAqC3B,IAAA,WAAA;;AAEU,IAAA,WAAwB;;QAAxB,IAAW,CAAA,WAAA,GAAX,WAAW,CAAa;AAnCjB,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,eAAe,CAAkB,EAAE,CAAC,CAAC;AAC1D,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,eAAe,CAAa,EAAE,CAAC,CAAC;QAC7C,IAAa,CAAA,aAAA,GAAG,IAAI,eAAe,CAClD,qBAAqB,CAAC,OAAO,CAC9B,CAAC;QACe,IAAW,CAAA,WAAA,GAAG,IAAI,eAAe,CAChD,qBAAqB,CAAC,OAAO,CAC9B,CAAC;AACe,QAAA,IAAA,CAAA,gBAAgB,GAAG,IAAI,eAAe,CAErD,EAAE,CAAC,CAAC;QACW,IAAkB,CAAA,kBAAA,GAAG,IAAI,eAAe,CAEvD,IAAI,GAAG,EAAU,CAAC,CAAC;;AAGrB,QAAA,IAAA,CAAA,eAAe,GACb,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;;AAErC,QAAA,IAAA,CAAA,OAAO,GAA2B,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;;AAE7D,QAAA,IAAA,CAAA,cAAc,GACZ,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;;AAEpC,QAAA,IAAA,CAAA,YAAY,GACV,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;;AAElC,QAAA,IAAA,CAAA,iBAAiB,GACf,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;;AAEvC,QAAA,IAAA,CAAA,mBAAmB,GACjB,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,CAAC;KAKrC;AAEJ;;;;;;;;AAQG;IACH,YAAY,CAAC,UAAkB,EAAE,eAAiC,EAAA;AAChE,QAAA,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;AAC7B,QAAA,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;KACxC;AAED;;;;;;;;;;AAUG;IACH,kBAAkB,GAAA;QAChB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AACvD,QAAA,MAAM,OAAO,GAA4B;AACvC,YAAA,OAAO,EAAE;AACP,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,UAAU,EAAE,oBAAoB;AAChC,gBAAA,cAAc,EAAE,IAAI;AACpB,gBAAA,IAAI,EAAE,CAAC;AACP,gBAAA,IAAI,EAAE,kBAAkB;AACxB,gBAAA,MAAM,EAAE;AACN,oBAAA,MAAM,EAAE,iBAAiB;AACzB,oBAAA,oBAAoB,EAAE,KAAK;AAC5B,iBAAA;AACF,aAAA;SACF,CAAC;QACF,OAAO,IAAI,CAAC,WAAW;aACpB,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,CAA6B,2BAAA,CAAA,EAAE,OAAO,CAAC;AAClE,aAAA,IAAI,CACH,GAAG,CAAC,CAAC,QAAkC,KAAI;AACzC,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,QAAQ,EAAE,IAAI,EAAE,gBAAgB,IAAI,EAAE,CACvC,CAAC;AACF,YAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjC,YAAA,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,aAAa,CAAC,IAAI,CACrB,MAAM,CAAC,MAAM,GAAG,CAAC;kBACb,qBAAqB,CAAC,MAAM;AAC9B,kBAAE,qBAAqB,CAAC,KAAK,CAChC,CAAC;;;AAGF,YAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AAC7B,YAAA,OAAO,QAAQ,CAAC;AAClB,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,KAAK,KAAI;YACnB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACrD,YAAA,MAAM,KAAK,CAAC;SACb,CAAC,CACH,CAAC;KACL;AAED;;;;;;;;;;;;AAYG;IACH,iBAAiB,CACf,OAAe,EACf,IAAI,GAAG,CAAC,EACR,IAAI,GAAG,wBAAwB,EAAA;AAE/B,QAAA,OAAO,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAC1D,GAAG,CAAC,CAAC,QAAoC,KAAI;AAC3C,YAAA,MAAM,QAAQ,GAAG,sBAAsB,CACrC,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE,CAC/B,CAAC;YACF,MAAM,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC;;;YAG9D,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAC7C,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,KAAK,OAAO,CACrC,CAAC;AACF,YAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CACnC,CAAC,OAAO,KAAK,OAAO,CAAC,mBAAmB,CACzC,CAAC,MAAM,CAAC;AACT,YAAA,MAAM,sBAAsB,GAC1B,QAAQ,EAAE,sBAAsB,IAAI,aAAa,CAAC;YACpD,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;AAC1E,YAAA,IAAI,CAAC,gCAAgC,CAAC,QAAQ,CAAC,CAAC;AAChD,YAAA,OAAO,QAAQ,CAAC;AAClB,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,KAAK,KAAI;AACnB,YAAA,MAAM,KAAK,CAAC;SACb,CAAC,CACH,CAAC;KACH;AAED;;;;;;;;;;AAUG;AACK,IAAA,kBAAkB,CACxB,OAAe,EACf,QAAsB,EACtB,YAAoB,EACpB,sBAA8B,EAAA;AAE9B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,KAAI;AACnD,YAAA,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE;AAC7B,gBAAA,OAAO,KAAK,CAAC;AACd,aAAA;YACD,OAAO;AACL,gBAAA,GAAG,KAAK;gBACR,QAAQ;AACR,gBAAA,YAAY,EAAE,YAAY;gBAC1B,sBAAsB;aACvB,CAAC;AACJ,SAAC,CAAC,CAAC;AACH,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAChC;AAED;;;;;;;;;AASG;AACK,IAAA,eAAe,CAAC,MAAuB,EAAA;QAC7C,MAAM;AACH,aAAA,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;AACzE,aAAA,OAAO,CAAC,CAAC,KAAK,KAAI;YACjB,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,qBAAqB,CAAC;iBACjE,IAAI,CACH,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAC3B;AACA,iBAAA,SAAS,CAAC,CAAC,QAAQ,KAAI;gBACtB,IAAI,CAAC,QAAQ,EAAE;oBACb,OAAO;AACR,iBAAA;AACD,gBAAA,MAAM,QAAQ,GAAG,sBAAsB,CACrC,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE,CAC/B,CAAC;gBACF,MAAM,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC;AAC9D,gBAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAC/B,CAAC,OAAO,KAAK,OAAO,CAAC,mBAAmB,CACzC,CAAC,MAAM,CAAC;gBACT,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;AACvD,gBAAA,IAAI,CAAC,gCAAgC,CAAC,QAAQ,CAAC,CAAC;AAClD,aAAC,CAAC,CAAC;AACP,SAAC,CAAC,CAAC;KACN;AAED;;;;;;;;AAQG;AACK,IAAA,gBAAgB,CACtB,OAAe,EACf,YAAoB,EACpB,sBAA8B,EAAA;AAE9B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,KAC/C,KAAK,CAAC,OAAO,KAAK,OAAO;cACrB,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE;cAChE,KAAK,CACV,CAAC;AACF,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAChC;AAED;;;;;;;;;AASG;AACK,IAAA,sBAAsB,CAC5B,OAAe,EACf,IAAY,EACZ,IAAY,EAAA;AAEZ,QAAA,MAAM,OAAO,GAA8B;AACzC,YAAA,OAAO,EAAE;gBACP,OAAO;AACP,gBAAA,UAAU,EAAE,0BAA0B;AACtC,gBAAA,cAAc,EAAE,IAAI;gBACpB,IAAI;gBACJ,IAAI;AACJ,gBAAA,MAAM,EAAE;AACN,oBAAA,MAAM,EAAE,iBAAiB;AACzB,oBAAA,oBAAoB,EAAE,KAAK;AAC5B,iBAAA;AACF,aAAA;SACF,CAAC;AACF,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAC9B,CAAA,EAAG,IAAI,CAAC,UAAU,CAAA,yBAAA,CAA2B,EAC7C,OAAO,CACR,CAAC;KACH;AAED;;;;;;;;AAQG;IACH,UAAU,GAAA;QACR,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,WAAW;AACpB,aAAA,OAAO,CAAC,CAAG,EAAA,IAAI,CAAC,UAAU,mBAAmB,CAAC;AAC9C,aAAA,IAAI,CACH,GAAG,CAAC,CAAC,QAA6C,KAAI;YACpD,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,KACtD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CACrB,CAAC;AACF,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CACnB,MAAM,CAAC,MAAM,GAAG,CAAC;kBACb,qBAAqB,CAAC,MAAM;AAC9B,kBAAE,qBAAqB,CAAC,KAAK,CAChC,CAAC;AACF,YAAA,OAAO,QAAQ,CAAC;AAClB,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,KAAK,KAAI;YACnB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACnD,YAAA,MAAM,KAAK,CAAC;SACb,CAAC,CACH,CAAC;KACL;AAED;;;;;;;;;AASG;AACK,IAAA,QAAQ,CAAC,KAAkB,EAAA;;;;QAIjC,MAAM,WAAW,GACf,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE;AACjB,aAAA,GAAG,CAAC,CAAC,OAAO,KAAK,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;aAC9C,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC;AACxB,aAAA,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC;QAE/B,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,KAAK,EAAE,KAAK,CAAC,SAAS;YACtB,IAAI,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS,IAAI,gBAAgB;YAChE,WAAW;YACX,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW;YAC1D,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,gBAAgB;;AAE1D,YAAA,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;SACjC,CAAC;KACH;AAED;;;;;;;;AAQG;AACH,IAAA,aAAa,CACX,SAAiB,EAAA;AAEjB,QAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,qBAAqB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAChE,CAAC;QACF,OAAO,IAAI,CAAC,WAAW;aACpB,QAAQ,CAAC,CAAG,EAAA,IAAI,CAAC,UAAU,0BAA0B,EAAE,EAAE,SAAS,EAAE,CAAC;AACrE,aAAA,IAAI,CACH,GAAG,CAAC,CAAC,QAAQ,KAAI;AACf,YAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CACxB,yBAAyB,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAClE,CAAC;AACF,YAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAC9D,CAAC;AACF,YAAA,OAAO,QAAQ,CAAC;AAClB,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,KAAK,KAAI;;AAEnB,YAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAC9D,CAAC;AACF,YAAA,MAAM,KAAK,CAAC;SACb,CAAC,CACH,CAAC;KACL;AAED;;;;;;;;AAQG;AACH,IAAA,YAAY,CACV,SAAiB,EAAA;AAEjB,QAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,qBAAqB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAChE,CAAC;QACF,OAAO,IAAI,CAAC,WAAW;aACpB,QAAQ,CAAC,CAAG,EAAA,IAAI,CAAC,UAAU,4BAA4B,EAAE,EAAE,SAAS,EAAE,CAAC;AACvE,aAAA,IAAI,CACH,GAAG,CAAC,CAAC,QAAQ,KAAI;AACf,YAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CACxB,wBAAwB,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CACjE,CAAC;AACF,YAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAC9D,CAAC;AACF,YAAA,OAAO,QAAQ,CAAC;AAClB,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,KAAK,KAAI;;AAEnB,YAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAC1B,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAC9D,CAAC;AACF,YAAA,MAAM,KAAK,CAAC;SACb,CAAC,CACH,CAAC;KACL;AAED;;;;AAIG;IACH,2BAA2B,GAAA;AACzB,QAAA,OAAO,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;KACpC;AAED;;;;;;;;AAQG;AACK,IAAA,oBAAoB,CAAC,MAAuB,EAAA;AAClD,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;AACjE,QAAA,IAAI,CAAC,gCAAgC,CAAC,QAAQ,CAAC,CAAC;KACjD;AAED;;;;;;;;AAQG;AACK,IAAA,gCAAgC,CAAC,QAAsB,EAAA;AAC7D,QAAA,MAAM,IAAI,GAAoC;AAC5C,YAAA,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK;SAC/B,CAAC;AACF,QAAA,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,KAAI;YAC3B,IAAI,OAAO,CAAC,SAAS,EAAE;AACrB,gBAAA,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;AACrB,oBAAA,OAAO,CAAC,eAAe;AACvB,wBAAA,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;wBACvB,eAAe,CAAC,aAAa,CAAC;AACjC,aAAA;AACH,SAAC,CAAC,CAAC;AACH,QAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAClC;+GA1cU,gBAAgB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAC,IAAA,CAAA,WAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA,EAAA;AAAhB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cAFf,MAAM,EAAA,CAAA,CAAA,EAAA;;4FAEP,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAH5B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA,CAAA;;;AC3ED;;;;AAIG;AACH;IACY,wBAGX;AAHD,CAAA,UAAY,uBAAuB,EAAA;AACjC,IAAA,uBAAA,CAAA,gBAAA,CAAA,GAAA,gBAAiC,CAAA;AACjC,IAAA,uBAAA,CAAA,eAAA,CAAA,GAAA,eAA+B,CAAA;AACjC,CAAC,EAHW,uBAAuB,KAAvB,uBAAuB,GAGlC,EAAA,CAAA,CAAA,CAAA;AACD;MAKa,sBAAsB,CAAA;AACjC;;;;;;AAMG;IACH,wBAAwB,CACtB,UAAmC,EACnC,eAAiC,EAAA;AAEjC,QAAA,MAAM,WAAW,GACf,eAAe,EAAE,MAAM,GAAG,CAAC;AACzB,cAAE,eAAe,EAAE,IAAI,CACnB,CAAC,EAAE,cAAc,EAAE,KAAK,cAAc,KAAK,UAAU,CACtD;cACD,KAAK,CAAC;AACZ,QAAA,OAAO,WAAW,CAAC;KACpB;AAED;;;;;AAKG;AACH,IAAA,gCAAgC,CAC9B,eAAiC,EAAA;QAEjC,OAAO;YACL,gBAAgB,EAAE,IAAI,CAAC,wBAAwB,CAC7C,uBAAuB,CAAC,cAAc,EACtC,eAAe,CAChB;YACD,eAAe,EAAE,IAAI,CAAC,wBAAwB,CAC5C,uBAAuB,CAAC,aAAa,EACrC,eAAe,CAChB;SACF,CAAC;KACH;+GAxCU,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA,EAAA;AAAtB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cAFrB,MAAM,EAAA,CAAA,CAAA,EAAA;;4FAEP,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAHlC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA,CAAA;;;AC6BD;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MAgBU,kBAAkB,CAAA;AA8D7B;;;;;AAKG;AACH,IAAA,IAAI,aAAa,GAAA;QACf,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAC/B,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC,EACpD,CAAC,CACF,CAAC;KACH;AAED;;;;;AAKG;AACH,IAAA,IAAI,WAAW,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;KAC3B;AAWD,IAAA,WAAA;;IAEU,gBAAkC;;IAElC,sBAA8C;;IAE9C,yBAAoD;;AAEpD,IAAA,YAA2B;;QAN3B,IAAgB,CAAA,gBAAA,GAAhB,gBAAgB,CAAkB;QAElC,IAAsB,CAAA,sBAAA,GAAtB,sBAAsB,CAAwB;QAE9C,IAAyB,CAAA,yBAAA,GAAzB,yBAAyB,CAA2B;QAEpD,IAAY,CAAA,YAAA,GAAZ,YAAY,CAAe;;QApGrC,IAAS,CAAA,SAAA,GAAGD,WAAS,CAAC;;AAeZ,QAAA,IAAA,CAAA,iBAAiB,GAAG,IAAI,YAAY,EAA6B,CAAC;;QAG5E,IAAc,CAAA,cAAA,GAAoB,EAAE,CAAC;;QAGrC,IAAM,CAAA,MAAA,GAAe,EAAE,CAAC;;AAGxB,QAAA,IAAA,CAAA,aAAa,GAA0B,qBAAqB,CAAC,OAAO,CAAC;;AAGrE,QAAA,IAAA,CAAA,WAAW,GAA0B,qBAAqB,CAAC,OAAO,CAAC;;QAGnE,IAAgB,CAAA,gBAAA,GAAoC,EAAE,CAAC;;AAGvD,QAAA,IAAA,CAAA,kBAAkB,GAAwB,IAAI,GAAG,EAAU,CAAC;;AAG5D,QAAA,IAAA,CAAA,qBAAqB,GAAgC;AACnD,YAAA,gBAAgB,EAAE,KAAK;AACvB,YAAA,eAAe,EAAE,KAAK;SACvB,CAAC;;QAGF,IAAY,CAAA,YAAA,GAAG,KAAK,CAAC;;QAGrB,IAAgB,CAAA,gBAAA,GAAG,KAAK,CAAC;;QAGzB,IAAc,CAAA,cAAA,GAAG,KAAK,CAAC;;QAoCvB,IAAe,CAAA,eAAA,GAAG,CAAC,CAAC;;QAGpB,IAAc,CAAA,cAAA,GAAG,CAAC,CAAC;;AAGF,QAAA,IAAA,CAAA,QAAQ,GAAG,IAAI,OAAO,EAAW,CAAC;KAW/C;AAEJ;;;;;;;;AAQG;IACH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;AAC1E,QAAA,IAAI,CAAC,qBAAqB;YACxB,IAAI,CAAC,sBAAsB,CAAC,gCAAgC,CAC1D,IAAI,CAAC,eAAe,CACrB,CAAC;QAEJ,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,EAAE,CAAC;KACnB;AAED;;;;AAIG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;KAC1B;AAED;;;;;;AAMG;IACH,oBAAoB,GAAA;;KAEnB;AAED;;;;;;;AAOG;AACH,IAAA,gBAAgB,CAAC,MAA2B,EAAA;AAC1C,QAAA,MAAM,OAAO,GACX,MAAM,KAAK,mBAAmB,CAAC,QAAQ;cACnC,IAAI,CAAC,eAAe;AACtB,cAAE,IAAI,CAAC,aAAa,CAAC;AAEzB,QAAA,IAAI,MAAM,KAAK,mBAAmB,CAAC,QAAQ,EAAE;AAC3C,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;AAC9B,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;AAC5B,SAAA;;QAGD,UAAU,CAAC,MAAK;AACd,YAAA,OAAO,EAAE,aAAa,EAAE,cAAc,CAAC;AACrC,gBAAA,QAAQ,EAAE,QAAQ;AAClB,gBAAA,KAAK,EAAE,OAAO;AACf,aAAA,CAAC,CAAC;AACL,SAAC,CAAC,CAAC;KACJ;AAED;;;;;AAKG;IACH,eAAe,GAAA;QACb,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;KAC3D;AAED;;;;;;AAMG;AACH,IAAA,WAAW,CAAC,OAAe,EAAA;QACzB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;KAClE;AAED;;;;;;AAMG;AACH,IAAA,aAAa,CAAC,SAAiB,EAAA;QAC7B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;KACtE;AAED;;;;;AAKG;IACH,eAAe,GAAA;QACb,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;KAC3D;AAED;;;;;;AAMG;AACH,IAAA,eAAe,CAAC,OAAe,EAAA;QAC7B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;KAClE;AAED;;;;;;AAMG;AACH,IAAA,kBAAkB,CAAC,IAAgB,EAAA;AACjC,QAAA,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC;AACtC,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC;KACrC;AAED;;;;;;;AAOG;AACH,IAAA,mBAAmB,CAAC,OAA0C,EAAA;AAC5D,QAAA,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE;YACrB,OAAO;AACR,SAAA;AACD,QAAA,IAAI,CAAC,gBAAgB;aAClB,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC;AAChD,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC;AACT,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,mBAAmB,EAAE;AACxC,SAAA,CAAC,CAAC;KACN;AAED;;;;;;;AAOG;AACH,IAAA,eAAe,CAAC,SAAiB,EAAA;AAC/B,QAAA,IAAI,CAAC,gBAAgB;aAClB,aAAa,CAAC,SAAS,CAAC;AACxB,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC;AACT,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,mBAAmB,EAAE;AACxC,SAAA,CAAC,CAAC;KACN;AAED;;;;;;;AAOG;AACH,IAAA,cAAc,CAAC,SAAiB,EAAA;AAC9B,QAAA,IAAI,CAAC,gBAAgB;aAClB,YAAY,CAAC,SAAS,CAAC;AACvB,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC;AACT,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,mBAAmB,EAAE;AACxC,SAAA,CAAC,CAAC;KACN;AAED;;;;;;AAMG;AACH,IAAA,IAAY,iBAAiB,GAAA;QAC3B,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;KAC7D;AAED;;;;;;AAMG;IACK,uBAAuB,GAAA;QAC7B,IAAI,CAAC,gBAAgB,CAAC,eAAe;AAClC,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,MAAM,MAAM,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC;QAEzD,IAAI,CAAC,gBAAgB,CAAC,OAAO;AAC1B,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,MAAM,KAAI;AACpB,YAAA,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;AACvB,SAAC,CAAC,CAAC;QAEL,IAAI,CAAC,gBAAgB,CAAC,cAAc;AACjC,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC;QAEtD,IAAI,CAAC,gBAAgB,CAAC,YAAY;AAC/B,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,gBAAgB,CAAC,iBAAiB;AACpC,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,MAAM,MAAM,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC;QAE3D,IAAI,CAAC,gBAAgB,CAAC,mBAAmB;AACtC,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAC,CAAC,CAAC;KACxD;AAED;;;;;AAKG;IACK,qBAAqB,GAAA;AAC3B,QAAA,IAAI,CAAC,yBAAyB;AAC3B,aAAA,aAAa,EAAE;AACf,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC,CAAC,MAA4B,KAAI;AAC1C,YAAA,IAAI,CAAC,YAAY,GAAG,MAAM,EAAE,OAAO,CAAC;AACtC,SAAC,CAAC,CAAC;KACN;AAED;;;;;AAKG;IACK,kBAAkB,GAAA;AACxB,QAAA,IAAI,CAAC,gBAAgB;AAClB,aAAA,kBAAkB,EAAE;AACpB,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC;AACT,YAAA,KAAK,EAAE,OAAO,IAAI,CAAC,aAAa,GAAG,qBAAqB,CAAC,KAAK,CAAC;AAChE,SAAA,CAAC,CAAC;KACN;AAED;;;;;;AAMG;IACK,UAAU,GAAA;AAChB,QAAA,IAAI,CAAC,gBAAgB;AAClB,aAAA,UAAU,EAAE;AACZ,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9B,aAAA,SAAS,CAAC;AACT,YAAA,KAAK,EAAE,OAAO,IAAI,CAAC,WAAW,GAAG,qBAAqB,CAAC,KAAK,CAAC;AAC9D,SAAA,CAAC,CAAC;KACN;AAED;;;;;;;AAOG;IACK,cAAc,CAAC,IAAY,EAAE,EAAW,EAAA;QAC9C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;KAC3D;AAED;;;;;AAKG;IACK,mBAAmB,GAAA;AACzB,QAAA,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;AAC7B,YAAA,MAAM,EAAE,QAAQ;AAChB,YAAA,OAAO,EACL,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY;gBACxC,qDAAqD;YACvD,SAAS,EAAE,SAAS,CAAC,KAAK;AAC1B,YAAA,aAAa,EAAE,IAAI;AACpB,SAAA,CAAC,CAAC;KACJ;+GA/ZU,kBAAkB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAE,gBAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,sBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,yBAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,IAAA,CAAA,aAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;AAAlB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,kBAAkB,8OAFlB,CAAC,aAAa,CAAC,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,IAAA,EA2DY,UAAU,EAEZ,EAAA,EAAA,YAAA,EAAA,eAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,eAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,IAAA,EAAA,UAAU,ECjJhD,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,qoDA4CA,gySDgCI,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAC,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACZ,+BAA+B,EAC/B,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,cAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,cAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,EAAA,WAAA,EAAA,aAAA,EAAA,eAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,mBAAmB,mNACnB,+BAA+B,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,eAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAOtB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAf9B,SAAS;+BAEE,kBAAkB,EAAA,UAAA,EAChB,IAAI,EACP,OAAA,EAAA;wBACP,YAAY;wBACZ,+BAA+B;wBAC/B,mBAAmB;wBACnB,+BAA+B;AAChC,qBAAA,EAAA,aAAA,EAGc,iBAAiB,CAAC,IAAI,EAC1B,SAAA,EAAA,CAAC,aAAa,CAAC,EAAA,QAAA,EAAA,qoDAAA,EAAA,MAAA,EAAA,CAAA,yuSAAA,CAAA,EAAA,CAAA;4MAOjB,UAAU,EAAA,CAAA;sBAAlB,KAAK;gBAGG,UAAU,EAAA,CAAA;sBAAlB,KAAK;gBAGG,QAAQ,EAAA,CAAA;sBAAhB,KAAK;gBAGG,eAAe,EAAA,CAAA;sBAAvB,KAAK;gBAGI,iBAAiB,EAAA,CAAA;sBAA1B,MAAM;gBAyCP,eAAe,EAAA,CAAA;sBADd,SAAS;AAAC,gBAAA,IAAA,EAAA,CAAA,iBAAiB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAA;gBAGlD,aAAa,EAAA,CAAA;sBADZ,SAAS;AAAC,gBAAA,IAAA,EAAA,CAAA,eAAe,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAA;;;;;;;;AE5IlD;;;;;;;AAOG;MAUU,yBAAyB,CAAA;AATtC,IAAA,WAAA,GAAA;QAUE,IAAS,CAAA,SAAA,GAAGL,WAAS,CAAC;QAEd,IAAgB,CAAA,gBAAA,GAAG,EAAE,CAAC;;AAY9B,QAAA,IAAA,CAAA,OAAO,GAAa,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AAgD3C,KAAA;IA1DC,IACI,WAAW,CAAC,KAAa,EAAA;AAC3B,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;KACzD;AACD,IAAA,IAAI,WAAW,GAAA;QACb,OAAO,IAAI,CAAC,gBAAgB,CAAC;KAC9B;AAKD;;;;;;;AAOG;AACK,IAAA,YAAY,CAAC,WAAmB,EAAA;QACtC,OAAO;AACL,YAAA;AACE,gBAAA,KAAK,EAAE,WAAW;AAClB,gBAAA,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC;AAC1C,gBAAA,SAAS,EAAE,CAAC;AACb,aAAA;SACF,CAAC;KACH;AAED;;;;;;;AAOG;AACK,IAAA,iBAAiB,CAAC,WAAmB,EAAA;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,QAEjC,CAAC;AACd,QAAA,MAAM,KAAK,GACT,QAAQ,GAAG,WAAW,CAAC,IAAI,QAAQ,GAAG,SAAS,CAAC,IAAI,uBAAuB,CAAC;AAC9E,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;KACjC;AAED;;;;;;AAMG;AACK,IAAA,YAAY,CAAC,KAAa,EAAA;AAChC,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC5E,QAAA,OAAO,CAA8B,2BAAA,EAAA,UAAU,IAAI,SAAS,EAAE,CAAC;KAChE;+GA9DU,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA,EAAA;AAAzB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,yBAAyB,ECtBtC,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,gNASA,EDQY,MAAA,EAAA,CAAA,qqTAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,YAAY,mIAAE,eAAe,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA,EAAA;;4FAK5B,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBATrC,SAAS;+BAEE,2BAA2B,EAAA,UAAA,EACzB,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,eAAe,CAAC,EAAA,aAAA,EAGzB,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,gNAAA,EAAA,MAAA,EAAA,CAAA,qqTAAA,CAAA,EAAA,CAAA;8BAQjC,WAAW,EAAA,CAAA;sBADd,KAAK;;;MEpBK,eAAe,CAAA;+GAAf,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA,EAAA;gHAAf,eAAe,EAAA,OAAA,EAAA,CAHhB,kBAAkB,CAAA,EAAA,OAAA,EAAA,CAClB,kBAAkB,CAAA,EAAA,CAAA,CAAA,EAAA;AAEjB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,YAHhB,kBAAkB,CAAA,EAAA,CAAA,CAAA,EAAA;;4FAGjB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAJ3B,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,OAAO,EAAE,CAAC,kBAAkB,CAAC;oBAC7B,OAAO,EAAE,CAAC,kBAAkB,CAAC;AAC9B,iBAAA,CAAA;;;ACJY,MAAA,gBAAgB,GAAW;AACtC,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,aAAa,EAAE,MACb,mEAA+B,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC;AACpE,KAAA;;;ACPH;;;;;AAKG;;ACHU,MAAA,uBAAuB,GAAyB;AAC3D,IAAA,WAAW,EAAE,gCAAgC;AAC7C,IAAA,aAAa,EAAE,kCAAkC;AACjD;;;;;AAKG;AACH,IAAA,WAAW,EAAE,QAAQ;AACrB,IAAA,aAAa,EAAE,+CAA+C;AAC9D,IAAA,aAAa,EAAE,QAAQ;;;ACXZ,MAAA,4BAA4B,GAAqB;AAC5D,IAAA;AACE,QAAA,cAAc,EAAE,aAAa;AAC7B,QAAA,YAAY,EAAE,2CAA2C;AAC1D,KAAA;AACD,IAAA;AACE,QAAA,cAAc,EAAE,eAAe;AAC/B,QAAA,YAAY,EAAE,2CAA2C;AAC1D,KAAA;AACD,IAAA;AACE,QAAA,cAAc,EAAE,aAAa;AAC7B,QAAA,YAAY,EAAE,2CAA2C;AAC1D,KAAA;AACD,IAAA;AACE,QAAA,cAAc,EAAE,gBAAgB;AAChC,QAAA,YAAY,EAAE,2CAA2C;AAC1D,KAAA;AACD,IAAA;AACE,QAAA,cAAc,EAAE,eAAe;AAC/B,QAAA,YAAY,EAAE,2CAA2C;AAC1D,KAAA;;;ACdH;;;;;;;;;AASG;AACU,MAAA,2BAA2B,GAAoB;AAC1D,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,gBAAgB,CAAC,KAAK;AAC5B,QAAA,KAAK,EAAE,6BAA6B;AACpC,QAAA,MAAM,EAAE,aAAa;AACrB,QAAA,YAAY,EAAE,YAAY;AAC1B,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,sBAAsB,EAAE,CAAC;AACzB,QAAA,SAAS,EAAE,qBAAqB;AAChC,QAAA,OAAO,EAAE,qBAAqB;AAC9B,QAAA,QAAQ,EAAE,kBAAkB;AAC5B,QAAA,QAAQ,EAAE;AACR,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,iBAAiB;AAC9B,gBAAA,gBAAgB,EAAE,qBAAqB;AACvC,gBAAA,cAAc,EAAE,kBAAkB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,IAAI;gBACzB,eAAe,EAAE,eAAe,CAAC,mBAAmB;AACrD,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,gCAAgC;AAC7C,gBAAA,gBAAgB,EAAE,4BAA4B;;AAE9C,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,IAAI;gBACzB,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,gCAAgC;;AAE7C,gBAAA,gBAAgB,EAAE,EAAE;AACpB,gBAAA,cAAc,EAAE,UAAU;AAC1B,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,IAAI;gBACzB,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,kBAAkB;AAC/B,gBAAA,gBAAgB,EAAE,sBAAsB;AACxC,gBAAA,cAAc,EAAE,UAAU;AAC1B,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,KAAK;gBAC1B,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,uBAAuB;AACpC,gBAAA,gBAAgB,EAAE,8BAA8B;AAChD,gBAAA,cAAc,EAAE,UAAU;AAC1B,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,IAAI;gBACzB,eAAe,EAAE,eAAe,CAAC,mBAAmB;AACrD,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,iBAAiB;AAC9B,gBAAA,gBAAgB,EAAE,qBAAqB;AACvC,gBAAA,cAAc,EAAE,kBAAkB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,kBAAkB;AAC5B,gBAAA,mBAAmB,EAAE,KAAK;gBAC1B,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACF,SAAA;AACF,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,gBAAgB,CAAC,KAAK;AAC5B,QAAA,KAAK,EAAE,mCAAmC;AAC1C,QAAA,MAAM,EAAE,UAAU;AAClB,QAAA,YAAY,EAAE,YAAY;AAC1B,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,sBAAsB,EAAE,CAAC;AACzB,QAAA,SAAS,EAAE,qBAAqB;AAChC,QAAA,OAAO,EAAE,qBAAqB;AAC9B,QAAA,QAAQ,EAAE,qBAAqB;AAC/B,QAAA,QAAQ,EAAE;AACR,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,uBAAuB;AACpC,gBAAA,gBAAgB,EAAE,iBAAiB;AACnC,gBAAA,cAAc,EAAE,cAAc;AAC9B,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,qBAAqB;AAC/B,gBAAA,mBAAmB,EAAE,IAAI;gBACzB,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,uBAAuB;;AAEpC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,qBAAqB;AAC/B,gBAAA,mBAAmB,EAAE,KAAK;gBAC1B,eAAe,EAAE,eAAe,CAAC,aAAa;AAC/C,aAAA;AACD,YAAA;AACE,gBAAA,SAAS,EAAE,SAAS;AACpB,gBAAA,WAAW,EAAE,wBAAwB;AACrC,gBAAA,gBAAgB,EAAE,iBAAiB;AACnC,gBAAA,cAAc,EAAE,cAAc;AAC9B,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,WAAW,EAAE,qBAAqB;AAClC,gBAAA,QAAQ,EAAE,qBAAqB;AAC/B,gBAAA,mBAAmB,EAAE,KAAK;gBAC1B,eAAe,EAAE,eAAe,CAAC,mBAAmB;AACrD,aAAA;AACF,SAAA;AACF,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,gBAAgB,CAAC,KAAK;AAC5B,QAAA,KAAK,EAAE,uBAAuB;AAC9B,QAAA,MAAM,EAAE,UAAU;;AAElB,QAAA,YAAY,EAAE,CAAC;AACf,QAAA,sBAAsB,EAAE,CAAC;AACzB,QAAA,SAAS,EAAE,qBAAqB;AAChC,QAAA,OAAO,EAAE,qBAAqB;AAC9B,QAAA,QAAQ,EAAE,eAAe;AACzB,QAAA,QAAQ,EAAE,EAAE;AACb,KAAA;EACD;AAEF;;;;;AAKG;AACU,MAAA,iCAAiC,GAAe;AAC3D,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,WAAW,EAAE,iCAAiC;AAC9C,IAAA,gBAAgB,EAAE,EAAE;AACpB,IAAA,WAAW,EAAE,qBAAqB;AAClC,IAAA,WAAW,EAAE,qBAAqB;AAClC,IAAA,QAAQ,EAAE,kBAAkB;AAC5B,IAAA,mBAAmB,EAAE,KAAK;IAC1B,eAAe,EAAE,eAAe,CAAC,aAAa;EAC9C;AAEF;;;;;;;;AAQG;AACU,MAAA,mBAAmB,GAAe;AAC7C,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,KAAK,EAAE,qBAAqB;AAC5B,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,OAAO;AACpB,QAAA,WAAW,EAAE,eAAe;AAC5B,QAAA,WAAW,EAAE,eAAe;AAC7B,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,KAAK,EAAE,4BAA4B;AACnC,QAAA,IAAI,EAAE,cAAc;;AAEpB,QAAA,WAAW,EAAE,kBAAkB;AAC/B,QAAA,WAAW,EAAE,QAAQ;AACtB,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,KAAK,EAAE,sBAAsB;;AAE7B,QAAA,WAAW,EAAE,WAAW;AACxB,QAAA,WAAW,EAAE,QAAQ;AACtB,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,KAAK,EAAE,8BAA8B;AACrC,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,WAAW,EAAE,QAAQ;AACrB,QAAA,WAAW,EAAE,oBAAoB;AACjC,QAAA,WAAW,EAAE,kBAAkB;AAChC,KAAA;AACD,IAAA;AACE,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,KAAK,EAAE,iBAAiB;AACxB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,YAAY;AACzB,QAAA,WAAW,EAAE,kBAAkB;AAC/B,QAAA,WAAW,EAAE,eAAe;AAC7B,KAAA;;;AClOH;;AAEG;AAEH;;ACJA;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ieeesa-npm-dashboard.mjs","sources":["../../../projects/dashboard/src/lib/models/dashboard-section-state.model.ts","../../../projects/dashboard/src/lib/models/upcoming-event.model.ts","../../../projects/dashboard/src/lib/models/attendance-state.model.ts","../../../projects/dashboard/src/lib/assets/date-formats.ts","../../../projects/dashboard/src/lib/utils/date-format.util.ts","../../../projects/dashboard/src/lib/components/meeting-attendance-row/meeting-attendance-row.component.ts","../../../projects/dashboard/src/lib/components/meeting-attendance-row/meeting-attendance-row.component.html","../../../projects/dashboard/src/lib/components/event-group-card/event-group-card.component.ts","../../../projects/dashboard/src/lib/components/event-group-card/event-group-card.component.html","../../../projects/dashboard/src/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.ts","../../../projects/dashboard/src/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.html","../../../projects/dashboard/src/lib/components/welcome-header/dashboard-welcome-header.component.ts","../../../projects/dashboard/src/lib/components/welcome-header/dashboard-welcome-header.component.html","../../../projects/dashboard/src/lib/components/your-groups/your-groups.component.ts","../../../projects/dashboard/src/lib/components/your-groups/your-groups.component.html","../../../projects/dashboard/src/lib/utils/event-meeting-mapper.util.ts","../../../projects/dashboard/src/lib/services/attendance-reducers.ts","../../../projects/dashboard/src/lib/services/dashboard.service.ts","../../../projects/dashboard/src/lib/services/user-permissions.service.ts","../../../projects/dashboard/src/lib/dashboard.component.ts","../../../projects/dashboard/src/lib/dashboard.component.html","../../../projects/dashboard/src/lib/components/member-level-badge/member-level-badge.component.ts","../../../projects/dashboard/src/lib/components/member-level-badge/member-level-badge.component.html","../../../projects/dashboard/src/lib/dashboard.module.ts","../../../projects/dashboard/src/lib/dashboard.routes.ts","../../../projects/dashboard/src/lib/models/event-meeting-list-payload.model.ts","../../../projects/dashboard/src/lib/assets/dashboard-route-paths.mock.ts","../../../projects/dashboard/src/lib/assets/dashboard-user-permissions.mock.ts","../../../projects/dashboard/src/lib/assets/dashboard-mock.ts","../../../projects/dashboard/src/public-api.ts","../../../projects/dashboard/src/ieeesa-npm-dashboard.ts"],"sourcesContent":["/* eslint-disable no-unused-vars */\r\nexport enum DashboardSectionState {\r\n LOADING = 'LOADING',\r\n LOADED = 'LOADED',\r\n EMPTY = 'EMPTY',\r\n ERROR = 'ERROR',\r\n}\r\n","import { AttendanceState } from './attendance-state.model';\r\nimport { MeetingRow } from './meeting-row.model';\r\n\r\n/* eslint-disable no-unused-vars */\r\n/**\r\n * Discriminates how a row in the \"Upcoming Meetings & Events\" list is rendered.\r\n * EVENT rows render as an expandable event block that owns child meetings;\r\n * STANDALONE_MEETING rows render as a single meeting card and always sort LAST\r\n * within the list.\r\n */\r\nexport enum UpcomingItemKind {\r\n EVENT = 'EVENT',\r\n STANDALONE_MEETING = 'STANDALONE_MEETING',\r\n}\r\n/* eslint-enable no-unused-vars */\r\n\r\n/**\r\n * View model for a single entry in the \"Upcoming Meetings & Events\" section.\r\n *\r\n * When {@link kind} is `EVENT` the entry renders as the expandable event block\r\n * (header badge, title, \"Day X of Y\", meeting-count sub-line, dates/timezone,\r\n * View button, and the show/hide child-meeting list). When `kind` is\r\n * `STANDALONE_MEETING` the entry renders as a single standalone meeting card\r\n * (rendered after all events).\r\n *\r\n * `startEpochMs` / `endEpochMs` carry the raw epoch-milliseconds values from the\r\n * backend and are formatted with luxon `DateTime.fromMillis`. The legacy ISO\r\n * `startDate` / `endDate` fields are retained for existing fixtures/tests.\r\n */\r\nexport interface UpcomingEvent {\r\n eventId: string;\r\n /** EVENT vs. STANDALONE_MEETING render discriminator. */\r\n kind: UpcomingItemKind;\r\n title: string;\r\n status: string;\r\n dayIndicator?: string;\r\n meetingCount: number;\r\n /**\r\n * Paginator length for the drill-down meeting list — the count of the user's\r\n * tied upcoming meetings for this event (a subset of {@link meetingCount}).\r\n * Populated by the drill-down response; defaults to `meetingCount`.\r\n */\r\n meetingPageTotal?: number;\r\n openForAttendanceCount: number;\r\n /** Start date-time as an ISO-8601 string (or epoch ms for fixtures). */\r\n startDateTime?: string | number;\r\n /** End date-time as an ISO-8601 string (or epoch ms for fixtures). */\r\n endDateTime?: string | number;\r\n /** Legacy ISO start date, retained for fixtures/tests. */\r\n startDate?: string;\r\n /** Legacy ISO end date, retained for fixtures/tests. */\r\n endDate?: string;\r\n timezone: string;\r\n /** Owning group label, shown on standalone-meeting cards. */\r\n groupOrCommittee?: string;\r\n /** Room / location, shown on standalone-meeting cards. */\r\n roomOrLocation?: string;\r\n /** True when the user is a member of the owning group. */\r\n isMemberOfGroup?: boolean;\r\n /** STANDALONE only: the user's attendance state for this meeting. */\r\n attendanceState?: AttendanceState;\r\n /** The event's child meetings (empty / lazily loaded for EVENT rows). */\r\n meetings: MeetingRow[];\r\n}\r\n","/* eslint-disable no-unused-vars */\r\n/**\r\n * Per-meeting attendance state as returned by the home endpoints.\r\n * - NOT_ATTENDING: the user has not logged attendance (shows Log Attendance).\r\n * - CURRENTLY_ATTENDING: the user is logged in (shows Leave Meeting + pill).\r\n * - ATTENDED: the user attended and has since logged out.\r\n */\r\nexport enum AttendanceState {\r\n CURRENTLY_ATTENDING = 'CURRENTLY_ATTENDING',\r\n NOT_ATTENDING = 'NOT_ATTENDING',\r\n ATTENDED = 'ATTENDED',\r\n}\r\n","/**\r\n * Luxon format tokens used across the dashboard library for rendering\r\n * event/meeting dates, times, and timezones.\r\n *\r\n * These tokens follow the luxon `DateTime.toFormat()` convention\r\n * (NOT moment). New code in this library must use luxon exclusively.\r\n *\r\n * @see https://moment.github.io/luxon/#/formatting?id=table-of-tokens\r\n */\r\nexport const DateFormats = {\r\n /** ISO date used for request payloads, e.g. 2025-03-14. */\r\n requestPayloadFormat: 'yyyy-MM-dd',\r\n /** ISO date-time used for request payloads, e.g. 2025-03-14T09:30:00. */\r\n requestPayloadDateTimeFormat: \"yyyy-MM-dd'T'HH:mm:ss\",\r\n /** Human-readable date for display, e.g. 14 Mar 2025. */\r\n displayFormat: 'dd MMM yyyy',\r\n /** Human-readable long date for display, e.g. 14 March 2025. */\r\n displayLongFormat: 'dd MMMM yyyy',\r\n /** 24-hour time for display, e.g. 09:30. */\r\n timeFormat: 'HH:mm',\r\n /** 12-hour time with meridiem for display, e.g. 9:30 AM. */\r\n timeMeridiemFormat: 'h:mm a',\r\n /** Short timezone abbreviation for display, e.g. EST. */\r\n timezoneFormat: 'ZZZZ',\r\n /** Long timezone name for display, e.g. Eastern Standard Time. */\r\n timezoneLongFormat: 'ZZZZZ',\r\n};\r\n","/**\r\n * Pure luxon date/time formatting helpers for the dashboard library.\r\n *\r\n * The real \"events & meetings\" backend returns date-times as ISO-8601 strings\r\n * (e.g. \"2026-01-01T00:00:00\") together with a display timezone string\r\n * (e.g. \"(UTC-04:00) America/New_York\"). These helpers parse the ISO value and\r\n * render it in the item's own zone (never moment). A numeric epoch-milliseconds\r\n * value is also accepted for backward compatibility with fixtures/tests. All\r\n * helpers fall back gracefully to an empty string when the value is missing or\r\n * unparseable.\r\n */\r\nimport { DateTime } from 'luxon';\r\n\r\n/**\r\n * Extracts a luxon-usable IANA zone from a backend timezone string such as\r\n * \"(UTC-04:00) America/New_York\" or \"America/New_York\". Returns `undefined`\r\n * when no usable zone can be derived so luxon falls back to the local zone.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string | undefined} The IANA zone id, or undefined.\r\n */\r\nexport function extractIanaZone(\r\n timezone: string | undefined\r\n): string | undefined {\r\n if (!timezone) {\r\n return undefined;\r\n }\r\n // Strip a leading \"(UTC±HH:MM) \" offset prefix when present.\r\n const closingParen = timezone.indexOf(') ');\r\n const zone =\r\n closingParen > -1\r\n ? timezone.slice(closingParen + 2).trim()\r\n : timezone.trim();\r\n return zone.length > 0 ? zone : undefined;\r\n}\r\n\r\n/**\r\n * Parses a backend date-time value — either an ISO-8601 string\r\n * (e.g. \"2026-01-01T00:00:00\") or an epoch-milliseconds number — into a luxon\r\n * {@link DateTime} in the supplied timezone. The ISO value is treated as a wall\r\n * time in the item's zone so the rendered time matches the backend's intent.\r\n * Returns an invalid DateTime when the value is missing/unparseable.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {DateTime} The parsed luxon DateTime (may be invalid).\r\n */\r\nexport function parseBackendDateTime(\r\n value: string | number | undefined | null,\r\n timezone?: string\r\n): DateTime {\r\n const zone = extractIanaZone(timezone);\r\n if (value === undefined || value === null || value === '') {\r\n return DateTime.invalid('empty');\r\n }\r\n if (typeof value === 'number') {\r\n return zone\r\n ? DateTime.fromMillis(value, { zone })\r\n : DateTime.fromMillis(value);\r\n }\r\n // ISO string: parse as a wall time in the item's zone when known.\r\n const isoOptions = zone ? { zone } : {};\r\n const parsed = DateTime.fromISO(value, isoOptions);\r\n return parsed.isValid ? parsed : DateTime.fromISO(value);\r\n}\r\n\r\n/**\r\n * Formats a backend date-time value (ISO string or epoch ms) with luxon using\r\n * the supplied format token, honouring the supplied timezone. Returns an empty\r\n * string when the value is missing or invalid.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string} format - The luxon `toFormat` token.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The formatted value, or an empty string.\r\n */\r\nexport function formatBackendDateTime(\r\n value: string | number | undefined | null,\r\n format: string,\r\n timezone?: string\r\n): string {\r\n const parsed = parseBackendDateTime(value, timezone);\r\n return parsed.isValid ? parsed.toFormat(format) : '';\r\n}\r\n\r\n/**\r\n * Backward-compatible alias kept for existing callers. Accepts ISO strings or\r\n * epoch ms and formats them in the item's zone.\r\n * @param {string | number | undefined | null} value - The ISO string or epoch ms.\r\n * @param {string} format - The luxon `toFormat` token.\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The formatted value, or an empty string.\r\n */\r\nexport function formatEpoch(\r\n value: string | number | undefined | null,\r\n format: string,\r\n timezone?: string\r\n): string {\r\n return formatBackendDateTime(value, format, timezone);\r\n}\r\n\r\n/**\r\n * Computes a human \"Day X of Y\" indicator for a multi-day event from its start\r\n * and end date-times, relative to \"now\". Returns an empty string when the dates\r\n * are missing/invalid or the event spans a single day.\r\n * @param {string | number | undefined | null} start - Event start (ISO or epoch ms).\r\n * @param {string | number | undefined | null} end - Event end (ISO or epoch ms).\r\n * @param {string | undefined} timezone - The backend timezone string.\r\n * @return {string} The \"Day X of Y\" label, or an empty string.\r\n */\r\nexport function computeDayIndicator(\r\n start: string | number | undefined | null,\r\n end: string | number | undefined | null,\r\n timezone?: string\r\n): string {\r\n const zone = extractIanaZone(timezone);\r\n const startDt = parseBackendDateTime(start, timezone);\r\n const endDt = parseBackendDateTime(end, timezone);\r\n if (!startDt.isValid || !endDt.isValid) {\r\n return '';\r\n }\r\n const startDay = startDt.startOf('day');\r\n const endDay = endDt.startOf('day');\r\n const totalDays = Math.floor(endDay.diff(startDay, 'days').days) + 1;\r\n // Only meaningful for short, multi-day events (a conference-week style span).\r\n // Very long spans (e.g. a year-long series) are not shown as \"Day X of Y\".\r\n const MAX_DAY_INDICATOR_SPAN = 31;\r\n if (totalDays <= 1 || totalDays > MAX_DAY_INDICATOR_SPAN) {\r\n return '';\r\n }\r\n const now = (zone ? DateTime.now().setZone(zone) : DateTime.now()).startOf(\r\n 'day'\r\n );\r\n const clampedNow = now < startDay ? startDay : now > endDay ? endDay : now;\r\n const currentDay = Math.floor(clampedNow.diff(startDay, 'days').days) + 1;\r\n return `Day ${currentDay} of ${totalDays}`;\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { MeetingRow } from '../../models/meeting-row.model';\r\nimport { DateFormats } from '../../assets/date-formats';\r\nimport { formatEpoch } from '../../utils/date-format.util';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Meeting_Attendance_Row renders a single meeting within an event-group card:\r\n * the meeting-name link, group/committee, room/location, date, and\r\n * time+timezone (all luxon-formatted), together with the attendance action\r\n * button that drives the per-meeting attendance state machine.\r\n *\r\n * The component is purely presentational — it emits navigation and attendance\r\n * intents via `@Output()` and never performs navigation or HTTP itself. The\r\n * action button delegates to the pure `resolveAttendanceAction` handler so the\r\n * emit/guard logic is shared with the property-tested core (Property 1), and the\r\n * displayed state only advances when the host updates `attendanceState`.\r\n * @export\r\n * @class MeetingAttendanceRowComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-meeting-attendance-row',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './meeting-attendance-row.component.html',\r\n styleUrls: ['./meeting-attendance-row.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class MeetingAttendanceRowComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** The meeting rendered by this row. */\r\n @Input() meeting!: MeetingRow;\r\n\r\n /** The current attendance state controlling label/indicator and action. */\r\n @Input() attendanceState: AttendanceState = AttendanceState.NOT_ATTENDING;\r\n\r\n /** Whether an attendance action for this meeting is awaiting resolution. */\r\n @Input() isInFlight = false;\r\n\r\n /** Host permissions gating the log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /**\r\n * Renders the leaner \"standalone meeting\" variant used by standalone-meeting\r\n * cards (the group/location and status live on the parent card, so the row\r\n * only shows the TIME & TIMEZONE block and the attendance + View actions).\r\n */\r\n @Input() compact = false;\r\n\r\n /** Emits the meeting id when the meeting-name link is activated (Req 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the meeting id to request logging attendance (Req 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Emits the meeting id to request leaving the meeting (Req 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /**\r\n * Emits the owning event id + meeting id when the attendance button is\r\n * activated for an In-Progress meeting, so the host can navigate to the\r\n * view-meeting screen (where the real Log Attendance popup opens).\r\n */\r\n @Output() navigateToMeeting = new EventEmitter<{\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }>();\r\n\r\n /** Expose the enum to the template for state comparisons. */\r\n readonly AttendanceState = AttendanceState;\r\n\r\n /**\r\n * Whether the meeting is eligible for an attendance action (an attendance\r\n * button is rendered at all). The backend supplies an `attendanceState` for\r\n * every loggable meeting, so its presence is the eligibility signal. Rows the\r\n * backend deems ineligible carry no state and render no button.\r\n * @return {boolean} True when the meeting is attendance-eligible.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isEligibleForAttendance(): boolean {\r\n return !!this.meeting?.attendanceState;\r\n }\r\n\r\n /**\r\n * Whether the meeting is currently In Progress. Mirrors the attendance\r\n * library's `isMeetingActive`: the attendance button is only ENABLED during\r\n * the meeting; outside the meeting time it renders disabled with the inactive\r\n * message.\r\n * @return {boolean} True when the meeting status is 'In Progress'.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isMeetingActive(): boolean {\r\n return (this.meeting?.status ?? '').trim().toLowerCase() === 'in progress';\r\n }\r\n\r\n /** The inactive-button message shown when the meeting is not In Progress. */\r\n get inactiveMessage(): string {\r\n return (\r\n this.constants?.meetingRow?.inactiveMessage ??\r\n 'Attendance logging only available during meeting, Please contact your meeting administrator for any necessary corrections.'\r\n );\r\n }\r\n\r\n /**\r\n * Whether this row is actionable — a non-empty `meetingId` is required for the\r\n * meeting-name link and action button to emit anything (Req 7.10).\r\n * @return {boolean} True when the row has a usable meeting id.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isActionable(): boolean {\r\n return !!this.meeting?.meetingId;\r\n }\r\n\r\n /**\r\n * Whether the row is in the currently-attending state, which shows the\r\n * currently-attending indicator and the leave-meeting action (Req 7.5).\r\n * @return {boolean} True when the attendance state is `CURRENTLY_ATTENDING`.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isCurrentlyAttending(): boolean {\r\n return this.attendanceState === AttendanceState.CURRENTLY_ATTENDING;\r\n }\r\n\r\n /**\r\n * Whether the log-attendance button should be shown: whenever the row is not\r\n * currently attending. Mirrors the attendance library, which toggles between\r\n * Log Attendance and Leave Meeting purely on attendance state (no permission\r\n * gating).\r\n * @return {boolean} True when the log-attendance button is visible.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get showLogAttendanceButton(): boolean {\r\n // Shown for every eligible, not-currently-attending meeting. When the\r\n // meeting is not In Progress the button renders disabled (see isLogDisabled).\r\n return this.isEligibleForAttendance && !this.isCurrentlyAttending;\r\n }\r\n\r\n /**\r\n * Whether the Log Attendance button is disabled: outside the meeting time\r\n * (not In Progress) or while an attendance action is in flight. Matches the\r\n * view-meeting page, which disables the button with an inactive message when\r\n * the meeting is not active.\r\n * @return {boolean} True when the Log Attendance button should be disabled.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get isLogDisabled(): boolean {\r\n return !this.isMeetingActive || this.isInFlight || !this.isActionable;\r\n }\r\n\r\n /**\r\n * Whether the leave-meeting button should be shown: whenever the row is\r\n * currently attending. Mirrors the attendance library (no permission gating).\r\n * @return {boolean} True when the leave-meeting button is visible.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get showLeaveMeetingButton(): boolean {\r\n // Leave Meeting is only meaningful while the meeting is active.\r\n return (\r\n this.isEligibleForAttendance &&\r\n this.isCurrentlyAttending &&\r\n this.isMeetingActive\r\n );\r\n }\r\n\r\n /**\r\n * Resolves a group-or-committee / room-or-location field value, substituting\r\n * the empty-field placeholder from `constants.json` when the value is empty or\r\n * undefined (Req 7.2).\r\n * @param {string | undefined} value - The raw field value from the meeting.\r\n * @return {string} The value to display, or the empty-field placeholder.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n resolveFieldValue(value: string | undefined): string {\r\n const placeholder =\r\n this.constants?.meetingRow?.emptyFieldPlaceholder ?? '—';\r\n return value && value.trim().length > 0 ? value : placeholder;\r\n }\r\n\r\n /**\r\n * Formats the meeting date for display using the shared luxon display format\r\n * (Req 7.3). Falls back to the raw value when it cannot be parsed.\r\n * @return {string} The formatted meeting date.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get formattedDate(): string {\r\n const value =\r\n this.meeting?.startDateTime ?? this.meeting?.meetingDate;\r\n return formatEpoch(\r\n value,\r\n DateFormats.displayFormat,\r\n this.meeting?.timezone\r\n );\r\n }\r\n\r\n /**\r\n * Formats the meeting time + timezone for display using luxon (Req 7.3).\r\n * The timezone abbreviation from the meeting model is appended to the parsed\r\n * time. Falls back to the raw value when it cannot be parsed.\r\n * @return {string} The formatted meeting time with timezone.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get formattedTime(): string {\r\n const range = this.timeRange;\r\n const timezone = this.meeting?.timezone ?? '';\r\n if (!range) {\r\n return '';\r\n }\r\n return timezone ? `${range} ${timezone}` : range;\r\n }\r\n\r\n /**\r\n * The bold time range only (e.g. \"10:00–11:00\"), 12-hour with meridiem,\r\n * rendered dark per Figma.\r\n * @return {string} The formatted start–end time range.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get timeRange(): string {\r\n const timezone = this.meeting?.timezone ?? '';\r\n const start = formatEpoch(\r\n this.meeting?.startDateTime ?? this.meeting?.meetingTime,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const end = formatEpoch(\r\n this.meeting?.endDateTime,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n return end ? `${start} \\u2013 ${end}` : start;\r\n }\r\n\r\n /**\r\n * The timezone label only (light grey per Figma), wrapped in parentheses, or\r\n * an empty string when no timezone is present.\r\n * @return {string} The parenthesised timezone, or an empty string.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n get timezoneDisplay(): string {\r\n const timezone = this.meeting?.timezone ?? '';\r\n return timezone ? timezone : '';\r\n }\r\n\r\n /**\r\n * Handles activation of the attendance action button. Delegates to the pure\r\n * `resolveAttendanceAction` handler and emits exactly one event based on the\r\n * resolved action: `logAttendance` for `LOG_ATTENDANCE`, `leaveMeeting` for\r\n * `LEAVE_MEETING`, and nothing for `NONE` (empty id or in-flight)\r\n * (Req 7.7, 7.8, 7.9, 7.10, 13.6).\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n onAttendanceAction(): void {\r\n if (!this.isActionable || !this.isMeetingActive) {\r\n return;\r\n }\r\n // The Log Attendance / Leave Meeting popup lives on the view-meeting screen,\r\n // so the dashboard navigates there (with eventId + meetingId) and requests\r\n // the matching flow auto-open instead of calling the attendance API directly.\r\n this.navigateToMeeting.emit({\r\n eventId: this.meeting?.eventId ?? '',\r\n meetingId: this.meeting.meetingId,\r\n logAttendance: !this.isCurrentlyAttending,\r\n leaveMeeting: this.isCurrentlyAttending,\r\n });\r\n }\r\n\r\n /**\r\n * Handles activation of the meeting-name link. Emits the meeting id only when\r\n * the row is actionable (non-empty meeting id) (Req 7.4, 7.10).\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n onOpenMeeting(): void {\r\n if (!this.isActionable) {\r\n return;\r\n }\r\n // Navigate to the view-meeting screen (no popup auto-open) when the meeting\r\n // name link is clicked.\r\n this.navigateToMeeting.emit({\r\n eventId: this.meeting?.eventId ?? '',\r\n meetingId: this.meeting.meetingId,\r\n });\r\n }\r\n}\r\n","<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 <span class=\"ieeesa-meeting-attendance-row__time\">{{ timeRange }}</span><ng-container\r\n *ngIf=\"timezoneDisplay\"\r\n > <span class=\"ieeesa-meeting-attendance-row__tz\">{{ timezoneDisplay }}</span></ng-container>\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 <!-- Fixed-width slot reserved for the attending pill so the action buttons\r\n stay column-aligned whether or not the pill is shown. -->\r\n <span class=\"ieeesa-meeting-attendance-row__attending-slot\">\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 </span>\r\n\r\n <!-- Log-attendance button: shown for eligible meetings, disabled (with the\r\n inactive message) when the meeting is not In Progress. -->\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 [class.ieeesa-meeting-attendance-row__action-button--inactive]=\"isLogDisabled\"\r\n [disabled]=\"isLogDisabled\"\r\n [attr.title]=\"isLogDisabled ? inactiveMessage : null\"\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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport {\r\n MatPaginatorModule,\r\n PageEvent,\r\n} from '@angular/material/paginator';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { MeetingRow } from '../../models/meeting-row.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../../models/upcoming-event.model';\r\nimport { DateFormats } from '../../assets/date-formats';\r\nimport { MeetingAttendanceRowComponent } from '../meeting-attendance-row/meeting-attendance-row.component';\r\nimport { formatEpoch } from '../../utils/date-format.util';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Event_Group_Card renders a single upcoming event as a card: the status badge,\r\n * title, day indicator, meeting-count summary sub-line, start/end date, and\r\n * timezone (all luxon-formatted). It exposes a \"View Event\" action, a\r\n * show/hide toggle for the meeting list labeled with the open-for-attendance\r\n * count, the per-event meeting rows (one {@link MeetingAttendanceRowComponent}\r\n * per meeting on the current page), and a per-card paginator.\r\n *\r\n * The component is purely presentational — it emits navigation, attendance, and\r\n * pagination intents via `@Output()` and never performs navigation or HTTP\r\n * itself. Meeting-row outputs (`openMeeting`/`logAttendance`/`leaveMeeting`) are\r\n * bubbled upward unchanged so the container can delegate to the service.\r\n * @export\r\n * @class EventGroupCardComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-event-group-card',\r\n standalone: true,\r\n imports: [CommonModule, MatPaginatorModule, MeetingAttendanceRowComponent],\r\n templateUrl: './event-group-card.component.html',\r\n styleUrls: ['./event-group-card.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class EventGroupCardComponent {\r\n /** User-facing strings sourced from `constants.json`. */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** Enum reference for EVENT vs STANDALONE_MEETING comparisons in the template. */\r\n readonly itemKinds = UpcomingItemKind;\r\n\r\n /**\r\n * The event status slugified into a BEM modifier suffix (lowercase, spaces to\r\n * hyphens), e.g. \"In Progress\" -> \"in-progress\", used to colour the status\r\n * pill per status.\r\n * @return {string} The status modifier suffix.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get statusModifier(): string {\r\n return (this.event?.status ?? '')\r\n .trim()\r\n .toLowerCase()\r\n .replace(/\\s+/g, '-');\r\n }\r\n\r\n /** The upcoming event rendered by this card. */\r\n @Input() event!: UpcomingEvent;\r\n\r\n /** Host permissions gating the per-row log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Map of meeting id to current attendance state, passed down to each row. */\r\n @Input() attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** Set of meeting ids with an attendance action awaiting resolution. */\r\n @Input() inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** Whether the host has determined the viewport is at/below the mobile breakpoint. */\r\n @Input() isMobileView = false;\r\n\r\n /** Emits the event id when the \"View Event\" button is activated (Req 6.4). */\r\n @Output() viewEvent = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row's meeting-name link is activated (Req 6.7, 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row requests logging attendance (Req 6.7, 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a row requests leaving the meeting (Req 6.7, 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the requested page when the per-card paginator changes (Req 6.9, 3.3). */\r\n @Output() pageChange = new EventEmitter<PageChange>();\r\n\r\n /**\r\n * Emits the one-based page to load when the meeting list is opened (or paged)\r\n * so the container can lazily fetch the event's child meetings from the\r\n * backend. Standalone-meeting cards never emit this.\r\n */\r\n @Output() loadMeetings = new EventEmitter<{ page: number; size: number }>();\r\n\r\n /**\r\n * Bubbles the owning event id + meeting id when an attendance button is\r\n * activated for an In-Progress meeting, so the host can navigate to the\r\n * view-meeting screen (where the real Log Attendance popup opens).\r\n */\r\n @Output() navigateToMeeting = new EventEmitter<{\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }>();\r\n\r\n /** The default page size for the per-card meeting paginator. */\r\n readonly defaultPageSize = 5;\r\n\r\n /** Page-size options shown in the paginator dropdown (matches the app-wide paginator). */\r\n readonly pageSizeOptions = [5, 10, 15];\r\n\r\n /** The current zero-based page index of the meeting list. */\r\n pageIndex = 0;\r\n\r\n /** The current page size of the meeting list. */\r\n pageSize = this.defaultPageSize;\r\n\r\n /** Whether the meeting list is currently shown (toggled open). */\r\n isMeetingListOpen = false;\r\n\r\n /**\r\n * Whether this card renders a STANDALONE_MEETING (leaner single-meeting card\r\n * with no child-meeting list) rather than an expandable EVENT block.\r\n * @return {boolean} True for standalone-meeting cards.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandalone(): boolean {\r\n return this.event?.kind === UpcomingItemKind.STANDALONE_MEETING;\r\n }\r\n\r\n /**\r\n * The full list of meetings for the event, defaulting to an empty list when\r\n * the event has none.\r\n * @return {MeetingRow[]} The event's meetings.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetings(): MeetingRow[] {\r\n return this.event?.meetings ?? [];\r\n }\r\n\r\n /**\r\n * The total number of meetings for the event (paginator length). Uses the\r\n * backend `meetingCount` (the full total) rather than the length of the\r\n * currently loaded page, so the paginator can advance through every page.\r\n * @return {number} The total meeting count.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get totalMeetings(): number {\r\n return (\r\n this.event?.meetingPageTotal ??\r\n this.event?.meetingCount ??\r\n this.meetings.length\r\n );\r\n }\r\n\r\n /**\r\n * The meetings to render for the current page. The server returns exactly one\r\n * page of meetings into `event.meetings`, so the card renders them as-is\r\n * without local slicing (pagination is server-side).\r\n * @return {MeetingRow[]} The meetings on the current page.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get pagedMeetings(): MeetingRow[] {\r\n return this.meetings;\r\n }\r\n\r\n /**\r\n * The one-based index of the first meeting shown on the current page, or 0\r\n * when there are no meetings.\r\n * @return {number} The start index for the range template.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeStart(): number {\r\n return this.totalMeetings === 0 ? 0 : this.pageIndex * this.pageSize + 1;\r\n }\r\n\r\n /**\r\n * The one-based index of the last meeting shown on the current page, clamped\r\n * to the total meeting count.\r\n * @return {number} The end index for the range template.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeEnd(): number {\r\n return Math.min((this.pageIndex + 1) * this.pageSize, this.totalMeetings);\r\n }\r\n\r\n /**\r\n * The paginator range label (e.g. \"Showing 1-5 of 12\") built from the\r\n * `constants.json` range template with the current start/end/total values.\r\n * @return {string} The formatted range label.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get rangeLabel(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.paginator?.rangeTemplate ??\r\n 'Showing {start}-{end} of {total}';\r\n return template\r\n .replace('{start}', `${this.rangeStart}`)\r\n .replace('{end}', `${this.rangeEnd}`)\r\n .replace('{total}', `${this.totalMeetings}`);\r\n }\r\n\r\n /**\r\n * The meeting-count summary sub-line (e.g. \"12 meetings\") built from the\r\n * `constants.json` total template with the event's meeting count.\r\n * @return {string} The formatted meeting-count summary.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetingCountSummary(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.paginator?.totalTemplate ??\r\n '{total} meetings';\r\n return template.replace('{total}', `${this.event?.meetingCount ?? 0}`);\r\n }\r\n\r\n /**\r\n * The header sub-line: the group · location line for a STANDALONE meeting, or\r\n * the \"{n} meetings scheduled across the event\" summary for an EVENT when its\r\n * meeting count is known (hidden until the count is loaded so it never shows\r\n * \"0 meetings\").\r\n * @return {string} The sub-line text, or an empty string to hide it.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get subtitleText(): string {\r\n if (this.isStandalone) {\r\n const group = this.event?.groupOrCommittee ?? '';\r\n const location = this.event?.roomOrLocation ?? '';\r\n if (group && location) {\r\n return `${group} \\u00b7 ${location}`;\r\n }\r\n return group || location;\r\n }\r\n return (this.event?.meetingCount ?? 0) > 0 ? this.meetingCountSummary : '';\r\n }\r\n\r\n /**\r\n * The meeting-list show/hide toggle label. When the list is hidden the label\r\n * reads \"Show Meetings ({count} open for attendance)\" built from the\r\n * `constants.json` templates and the event's open-for-attendance count; when\r\n * the list is shown the label reads the configured hide label (Req 6.5).\r\n * @return {string} The toggle button label.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get meetingListToggleLabel(): string {\r\n const toggle = this.constants?.eventGroupCard?.meetingListToggle;\r\n if (this.isMeetingListOpen) {\r\n return toggle?.hideLabel ?? 'Hide meetings';\r\n }\r\n return toggle?.showLabel ?? 'Show meetings';\r\n }\r\n\r\n /**\r\n * The \"{count} Meetings open for attendance\" summary shown in the event's\r\n * meetings bar, built from the `constants.json` template and the event's\r\n * open-for-attendance count (Req 6.5).\r\n * @return {string} The formatted open-for-attendance summary.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get openForAttendanceSummary(): string {\r\n const template =\r\n this.constants?.eventGroupCard?.openForAttendanceTemplate ??\r\n '{count} Meetings open for attendance';\r\n return template.replace(\r\n '{count}',\r\n `${this.event?.openForAttendanceCount ?? 0}`\r\n );\r\n }\r\n\r\n /**\r\n * The {@link MeetingRow} view model for a STANDALONE_MEETING card, projected\r\n * from the event entry so the shared {@link MeetingAttendanceRowComponent}\r\n * renders its time/timezone block and attendance action.\r\n * @return {MeetingRow} The standalone meeting row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get standaloneMeeting(): MeetingRow {\r\n return {\r\n meetingId: this.event?.eventId ?? '',\r\n meetingName: this.event?.title ?? '',\r\n groupOrCommittee: this.event?.groupOrCommittee,\r\n roomOrLocation: this.event?.roomOrLocation,\r\n startDateTime: this.event?.startDateTime ?? this.event?.startDate,\r\n endDateTime: this.event?.endDateTime ?? this.event?.endDate,\r\n timezone: this.event?.timezone ?? '',\r\n status: this.event?.status,\r\n isMemberOfGroup: this.event?.isMemberOfGroup,\r\n };\r\n }\r\n\r\n /**\r\n * The formatted \"start – end time (timezone)\" string for a STANDALONE meeting,\r\n * mirroring the inner meeting row's TIME & TIMEZONE value.\r\n * @return {string} The formatted time + timezone.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get standaloneTime(): string {\r\n const timezone = this.event?.timezone ?? '';\r\n const start = formatEpoch(\r\n this.event?.startDateTime ?? this.event?.startDate,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const end = formatEpoch(\r\n this.event?.endDateTime ?? this.event?.endDate,\r\n DateFormats.timeMeridiemFormat,\r\n timezone\r\n );\r\n const range = end ? `${start} \\u2013 ${end}` : start;\r\n if (!range) {\r\n return '';\r\n }\r\n return timezone ? `${range} ${timezone}` : range;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting is currently being attended (drives the pill\r\n * and the leave action).\r\n * @return {boolean} True when the standalone meeting is currently attending.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandaloneAttending(): boolean {\r\n return (\r\n this.resolveAttendanceState(this.standaloneMeeting) ===\r\n AttendanceState.CURRENTLY_ATTENDING\r\n );\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting's Log Attendance button is shown (whenever\r\n * not currently attending). No permission gating — mirrors the attendance\r\n * library.\r\n * @return {boolean} True when the log-attendance button is visible.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get showStandaloneLog(): boolean {\r\n // Shown for every eligible, not-currently-attending standalone meeting.\r\n // Disabled (with the inactive message) when the meeting is not In Progress.\r\n return !this.isStandaloneAttending;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting's Leave Meeting button is shown — only while\r\n * the meeting is currently attending AND active.\r\n * @return {boolean} True when the leave-meeting button is visible.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get showStandaloneLeave(): boolean {\r\n return this.isStandaloneAttending && this.isStandaloneActive;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting is eligible for an attendance action. The\r\n * backend supplies an `attendanceState` only for attendance-eligible meetings\r\n * (open for attendance), so its presence is the eligibility signal.\r\n * @return {boolean} True when the standalone meeting is attendance-eligible.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandaloneEligible(): boolean {\r\n return !!this.event?.attendanceState;\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE meeting is currently In Progress — the attendance\r\n * button is only ENABLED during the meeting (disabled otherwise, mirroring the\r\n * view-meeting page).\r\n * @return {boolean} True when the standalone meeting status is 'In Progress'.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandaloneActive(): boolean {\r\n return (this.event?.status ?? '').trim().toLowerCase() === 'in progress';\r\n }\r\n\r\n /**\r\n * Whether the STANDALONE Log Attendance button is disabled (outside meeting\r\n * time), matching the view-meeting page's inactive state.\r\n * @return {boolean} True when the standalone log button should be disabled.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get isStandaloneLogDisabled(): boolean {\r\n return !this.isStandaloneActive;\r\n }\r\n\r\n /** The inactive-button message shown when the standalone meeting is not active. */\r\n get inactiveMessage(): string {\r\n return (\r\n this.constants?.meetingRow?.inactiveMessage ??\r\n 'Attendance logging only available during meeting, Please contact your meeting administrator for any necessary corrections.'\r\n );\r\n }\r\n\r\n /**\r\n * Bubbles a row's navigate-to-meeting request upward unchanged so the host can\r\n * route to the view-meeting screen.\r\n * @param {{ eventId: string; meetingId: string }} request - The meeting identity.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onNavigateToMeeting(request: {\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }): void {\r\n this.navigateToMeeting.emit(request);\r\n }\r\n\r\n /**\r\n * Emits the navigate-to-meeting intent for a STANDALONE meeting's attendance\r\n * action (Log Attendance or Leave Meeting, requesting the matching popup\r\n * auto-open). Its own id is the meeting id; it has no parent event.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onNavigateToStandalone(): void {\r\n if (!this.isStandaloneActive) {\r\n return;\r\n }\r\n this.navigateToMeeting.emit({\r\n eventId: '',\r\n meetingId: this.event?.eventId ?? '',\r\n logAttendance: !this.isStandaloneAttending,\r\n leaveMeeting: this.isStandaloneAttending,\r\n });\r\n }\r\n\r\n /**\r\n * Emits the navigate-to-meeting intent for a STANDALONE meeting's name link\r\n * (view only — no popup auto-open).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onOpenStandalone(): void {\r\n this.navigateToMeeting.emit({\r\n eventId: '',\r\n meetingId: this.event?.eventId ?? '',\r\n });\r\n }\r\n\r\n /** The luxon-formatted start date of the event (ISO or epoch ms) (Req 6.2). */\r\n get formattedStartDate(): string {\r\n return this.formatDate(\r\n this.event?.startDateTime ?? this.event?.startDate\r\n );\r\n }\r\n\r\n /** The luxon-formatted end date of the event (ISO or epoch ms) (Req 6.2). */\r\n get formattedEndDate(): string {\r\n return this.formatDate(this.event?.endDateTime ?? this.event?.endDate);\r\n }\r\n\r\n /**\r\n * `trackBy` for the meeting-row `*ngFor`, keyed by the stable meeting id so\r\n * Angular reuses row components across pagination/state changes (Req 6.7, 14.4).\r\n * @param {number} _index - The iteration index (unused).\r\n * @param {MeetingRow} meeting - The meeting for this row.\r\n * @return {string} The stable track key (meeting id).\r\n * @memberof EventGroupCardComponent\r\n */\r\n trackByMeetingId(_index: number, meeting: MeetingRow): string {\r\n return meeting?.meetingId ?? `${_index}`;\r\n }\r\n\r\n /**\r\n * Resolves the attendance state for a meeting from the `attendanceStates` map,\r\n * defaulting to `NOT_ATTENDING` when the map has no entry for it.\r\n * @param {MeetingRow} meeting - The meeting to resolve state for.\r\n * @return {AttendanceState} The attendance state passed to the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n resolveAttendanceState(meeting: MeetingRow): AttendanceState {\r\n return (\r\n this.attendanceStates?.[meeting?.meetingId] ??\r\n AttendanceState.NOT_ATTENDING\r\n );\r\n }\r\n\r\n /**\r\n * Resolves whether a meeting has an attendance action in flight from the\r\n * `inFlightMeetingIds` set.\r\n * @param {MeetingRow} meeting - The meeting to check.\r\n * @return {boolean} True when the meeting's action is awaiting resolution.\r\n * @memberof EventGroupCardComponent\r\n */\r\n resolveIsInFlight(meeting: MeetingRow): boolean {\r\n return this.inFlightMeetingIds?.has(meeting?.meetingId) ?? false;\r\n }\r\n\r\n /**\r\n * Toggles the meeting-list visibility, lazily requesting the first page of the\r\n * event's child meetings from the container the first time it is opened (Req 6.6).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onToggleMeetingList(): void {\r\n this.isMeetingListOpen = !this.isMeetingListOpen;\r\n if (this.isMeetingListOpen) {\r\n this.loadMeetings.emit({ page: this.pageIndex + 1, size: this.pageSize });\r\n }\r\n }\r\n\r\n /**\r\n * Handles the \"View Event\" button, emitting the event id to the host (Req 6.4).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onViewEvent(): void {\r\n this.viewEvent.emit(this.event?.eventId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's meeting-name link activation upward (Req 6.7, 7.4).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.openMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's log-attendance request upward (Req 6.7, 7.7).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.logAttendance.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a row's leave-meeting request upward (Req 6.7, 7.8).\r\n * @param {string} meetingId - The id emitted by the row.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.leaveMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Handles the per-card paginator change, updating the local page state and\r\n * emitting the requested page as a {@link PageChange} (Req 6.9, 3.3).\r\n * @param {PageEvent} event - The Material paginator page event.\r\n * @memberof EventGroupCardComponent\r\n */\r\n onPageChange(event: PageEvent): void {\r\n this.pageIndex = event.pageIndex;\r\n this.pageSize = event.pageSize;\r\n this.pageChange.emit({\r\n pageIndex: event.pageIndex,\r\n pageSize: event.pageSize,\r\n });\r\n // Request the newly selected page/size's child meetings from the container.\r\n this.loadMeetings.emit({ page: event.pageIndex + 1, size: event.pageSize });\r\n }\r\n\r\n /**\r\n * Formats a date for display, preferring the epoch-milliseconds value (from\r\n * the real API) formatted in the event's timezone and falling back to a legacy\r\n * ISO string. Returns an empty string when neither is present.\r\n * @param {number | undefined} epochMs - The epoch-milliseconds value.\r\n * @param {string | undefined} isoValue - The legacy ISO fallback.\r\n * @return {string} The formatted date or an empty string.\r\n * @memberof EventGroupCardComponent\r\n */\r\n private formatDate(value: string | number | undefined | null): string {\r\n return formatEpoch(value, DateFormats.displayFormat, this.event?.timezone);\r\n }\r\n}\r\n","<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 {{ 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-line\">\r\n <span class=\"ieeesa-event-group-card__dates-value\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate && formattedEndDate !== formattedStartDate\">\r\n – {{ formattedEndDate }}</ng-container>\r\n </span>\r\n <span\r\n *ngIf=\"event.timezone\"\r\n class=\"ieeesa-event-group-card__timezone-value\"\r\n >\r\n ({{ event.timezone }})\r\n </span>\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 bar: \"Meetings\" label (left), open-for-attendance count +\r\n Show/Hide toggle (right), matching the Figma layout. -->\r\n <div class=\"ieeesa-event-group-card__meetings-bar\">\r\n <span class=\"ieeesa-event-group-card__meetings-label\">\r\n {{ constants.eventGroupCard.meetingsLabel }}\r\n </span>\r\n\r\n <div class=\"ieeesa-event-group-card__meetings-bar-right\">\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 </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 (navigateToMeeting)=\"onNavigateToMeeting($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 <mat-paginator\r\n class=\"ieeesa-event-group-card__paginator-control\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSize]=\"pageSize\"\r\n [pageSizeOptions]=\"pageSizeOptions\"\r\n [length]=\"totalMeetings\"\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)=\"onOpenStandalone()\"\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 {{ 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. Shown only for attendance-eligible meetings. -->\r\n <div\r\n *ngIf=\"isStandaloneEligible\"\r\n class=\"ieeesa-event-group-card__standalone-actions\"\r\n >\r\n <span class=\"ieeesa-event-group-card__attending-slot\">\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 </span>\r\n\r\n <button\r\n *ngIf=\"!isStandaloneAttending\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--log\"\r\n [class.ieeesa-event-group-card__standalone-action--inactive]=\"isStandaloneLogDisabled\"\r\n [disabled]=\"isStandaloneLogDisabled\"\r\n [attr.title]=\"isStandaloneLogDisabled ? inactiveMessage : null\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.logAttendance\"\r\n (click)=\"onNavigateToStandalone()\"\r\n >\r\n {{ constants.meetingRow.logAttendanceLabel }}\r\n </button>\r\n\r\n <button\r\n *ngIf=\"isStandaloneAttending\"\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__standalone-action ieeesa-event-group-card__standalone-action--leave\"\r\n [attr.aria-label]=\"constants.meetingRow.ariaLabel.leaveMeeting\"\r\n (click)=\"onNavigateToStandalone()\"\r\n >\r\n {{ constants.meetingRow.leaveMeetingLabel }}\r\n </button>\r\n </div>\r\n </div>\r\n</article>\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport {\r\n MatPaginatorModule,\r\n PageEvent,\r\n} from '@angular/material/paginator';\r\nimport { LoaderComponent } from '@ieeesa-npm/presentation';\r\nimport { AttendanceActionPermissions } from '../../models/attendance-action-permissions.model';\r\nimport { AttendanceState } from '../../models/attendance-state.model';\r\nimport { DashboardSectionState } from '../../models/dashboard-section-state.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../../models/upcoming-event.model';\r\nimport { EventGroupCardComponent } from '../event-group-card/event-group-card.component';\r\nimport * as screenTexts from '../../assets/constants.json';\r\n\r\n/**\r\n * Upcoming_Meetings_Events renders the \"Upcoming Meetings & Events\" dashboard\r\n * section: a section title and \"View All\" link, a collapse/expand toggle that\r\n * starts expanded, and one {@link EventGroupCardComponent} per upcoming event.\r\n *\r\n * The section is driven by its `sectionState` input: it shows the Loader while\r\n * `LOADING`, the event-group cards while `LOADED`, the empty-state message while\r\n * `EMPTY`, and the error message while `ERROR` — the four regions are mutually\r\n * exclusive (Req 13.1, 13.2, 13.3, 13.5). The component is purely\r\n * presentational: \"View All\" emits `viewAll` (Req 5.1, 5.2), the collapse toggle\r\n * flips `isExpanded` and the card-list visibility while exposing\r\n * `[attr.aria-expanded]` (Req 5.3, 5.4, 14.3), and each card is rendered via\r\n * `*ngFor` with {@link trackByEventId} to preserve input order (Req 5.5, 5.6,\r\n * 14.4). Card outputs (`viewEvent`/`openMeeting`/`logAttendance`/`leaveMeeting`)\r\n * are bubbled upward unchanged, and each card's `pageChange` is mapped to\r\n * `meetingPageChange` tagged with the originating event id (Req 6.9).\r\n * @export\r\n * @class UpcomingMeetingsEventsComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-upcoming-meetings-events',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatPaginatorModule,\r\n LoaderComponent,\r\n EventGroupCardComponent,\r\n ],\r\n templateUrl: './upcoming-meetings-events.component.html',\r\n styleUrls: ['./upcoming-meetings-events.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class UpcomingMeetingsEventsComponent {\r\n /** User-facing strings sourced from `constants.json`. */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n constants: any = screenTexts;\r\n\r\n /** Enum reference for template comparisons against `sectionState`. */\r\n readonly sectionStates = DashboardSectionState;\r\n\r\n /** The upcoming events rendered as event-group cards (Req 5.5, 5.6). */\r\n @Input() events: UpcomingEvent[] = [];\r\n\r\n /** The load/empty/error status driving the section's mutually exclusive regions. */\r\n @Input() sectionState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** Host permissions gating the per-row log-attendance / leave-meeting buttons. */\r\n @Input() permissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Map of meeting id to current attendance state, passed down to each card. */\r\n @Input() attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** Set of meeting ids with an attendance action awaiting resolution. */\r\n @Input() inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** Whether the host has determined the viewport is at/below the mobile breakpoint. */\r\n @Input() isMobileView = false;\r\n\r\n /** Emits when the \"View All\" link is activated (Req 5.2). */\r\n @Output() viewAll = new EventEmitter<void>();\r\n\r\n /** Bubbles the event id when a card's \"View Event\" button is activated (Req 6.4). */\r\n @Output() viewEvent = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card's meeting-name link is activated (Req 7.4). */\r\n @Output() openMeeting = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card requests logging attendance (Req 7.7). */\r\n @Output() logAttendance = new EventEmitter<string>();\r\n\r\n /** Bubbles the meeting id when a card requests leaving the meeting (Req 7.8). */\r\n @Output() leaveMeeting = new EventEmitter<string>();\r\n\r\n /** Emits the requested page tagged with its event id when a card paginates (Req 6.9). */\r\n @Output() meetingPageChange = new EventEmitter<{ eventId: string } & PageChange>();\r\n\r\n /** Emits the event id + one-based page + size to lazily load an event's child meetings. */\r\n @Output() loadEventMeetings = new EventEmitter<{\r\n eventId: string;\r\n page: number;\r\n size: number;\r\n }>();\r\n\r\n /** Bubbles a navigate-to-meeting request (eventId + meetingId [+ logAttendance]) for the host to route. */\r\n @Output() navigateToMeeting = new EventEmitter<{\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }>();\r\n\r\n /** Whether the section's card list is currently expanded; starts collapsed. */\r\n isExpanded = false;\r\n\r\n /** Section-level page size — 5 events/meetings per page per the design. */\r\n readonly sectionPageSize = 5;\r\n\r\n /** The current zero-based page index of the section list. */\r\n sectionPageIndex = 0;\r\n\r\n /** The total number of events/meetings in the section (paginator length). */\r\n get totalItems(): number {\r\n return this.events?.length ?? 0;\r\n }\r\n\r\n /**\r\n * The slice of events/meetings for the current section page (5 per page),\r\n * used by the card `*ngFor`.\r\n * @return {UpcomingEvent[]} The events on the current page.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get pagedEvents(): UpcomingEvent[] {\r\n const start = this.sectionPageIndex * this.sectionPageSize;\r\n return (this.events ?? []).slice(start, start + this.sectionPageSize);\r\n }\r\n\r\n /** The one-based index of the first item shown on the current page. */\r\n get sectionRangeStart(): number {\r\n return this.totalItems === 0\r\n ? 0\r\n : this.sectionPageIndex * this.sectionPageSize + 1;\r\n }\r\n\r\n /** The one-based index of the last item shown on the current page. */\r\n get sectionRangeEnd(): number {\r\n return Math.min(\r\n (this.sectionPageIndex + 1) * this.sectionPageSize,\r\n this.totalItems\r\n );\r\n }\r\n\r\n /**\r\n * The section paginator range label (e.g. \"1-5 of 20 Meetings & Events\")\r\n * built from the `constants.json` template.\r\n * @return {string} The formatted range label.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get sectionRangeLabel(): string {\r\n const template =\r\n this.constants?.upcomingSection?.paginator?.rangeTemplate ??\r\n '{start}-{end} of {total} Meetings & Events';\r\n return template\r\n .replace('{start}', `${this.sectionRangeStart}`)\r\n .replace('{end}', `${this.sectionRangeEnd}`)\r\n .replace('{total}', `${this.totalItems}`);\r\n }\r\n\r\n /**\r\n * Handles the section paginator change, updating the current section page.\r\n * @param {PageEvent} event - The Material paginator page event.\r\n * @return {void}\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onSectionPageChange(event: PageEvent): void {\r\n this.sectionPageIndex = event.pageIndex;\r\n }\r\n\r\n /** Number of EVENT rows in the list (for the collapsed summary). */\r\n get eventCount(): number {\r\n return (this.events ?? []).filter(\r\n (entry) => entry.kind === UpcomingItemKind.EVENT\r\n ).length;\r\n }\r\n\r\n /**\r\n * Total number of meetings across the list: each event's `meetingCount` plus\r\n * one per standalone meeting (for the collapsed summary).\r\n * @return {number} The total meeting count.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get totalMeetingCount(): number {\r\n return (this.events ?? []).reduce((total, entry) => {\r\n return (\r\n total +\r\n (entry.kind === UpcomingItemKind.EVENT\r\n ? entry.meetingCount ?? 0\r\n : 1)\r\n );\r\n }, 0);\r\n }\r\n\r\n /**\r\n * Total number of meetings open for attendance across the list (for the\r\n * collapsed summary): each event's open count plus any standalone meeting that\r\n * is attendance-eligible.\r\n * @return {number} The total open-for-attendance count.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get totalOpenForAttendanceCount(): number {\r\n return (this.events ?? []).reduce((total, entry) => {\r\n if (entry.kind === UpcomingItemKind.EVENT) {\r\n return total + (entry.openForAttendanceCount ?? 0);\r\n }\r\n return total + (entry.attendanceState ? 1 : 0);\r\n }, 0);\r\n }\r\n\r\n /**\r\n * The collapsed summary line (e.g. \"3 events · 50 meetings · 21 open for\r\n * attendance\") built from the `constants.json` template and the counts.\r\n * @return {string} The formatted collapsed summary.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n get collapsedSummary(): string {\r\n const template =\r\n this.constants?.upcomingSection?.collapsedSummaryTemplate ??\r\n '{events} events \\u00b7 {meetings} meetings \\u00b7 {open} open for attendance';\r\n return template\r\n .replace('{events}', `${this.eventCount}`)\r\n .replace('{meetings}', `${this.totalMeetingCount}`)\r\n .replace('{open}', `${this.totalOpenForAttendanceCount}`);\r\n }\r\n\r\n /**\r\n * Allows the host/container to open or close the section (e.g. a \"Jump to\"\r\n * shortcut opens it). Writing the input mirrors the value onto the internal\r\n * expand state while leaving the user's own toggle free to change it after.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n @Input()\r\n set expanded(value: boolean) {\r\n this.isExpanded = !!value;\r\n }\r\n get expanded(): boolean {\r\n return this.isExpanded;\r\n }\r\n\r\n /**\r\n * Emits the new expanded state whenever the user toggles the section, so a\r\n * two-way `[(expanded)]` binding keeps the host's flag in sync (otherwise a\r\n * host-opened section the user then collapses leaves the host flag stale,\r\n * making a repeat \"Jump to\" a no-op).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n @Output() expandedChange = new EventEmitter<boolean>();\r\n\r\n /**\r\n * `trackBy` for the event-group-card `*ngFor`, keyed by the stable event id so\r\n * Angular renders exactly one card per event in input order (Req 5.5, 5.6, 14.4).\r\n * @param {number} index - The iteration index (fallback key).\r\n * @param {UpcomingEvent} event - The event for this card.\r\n * @return {string} The stable track key (event id).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n trackByEventId(index: number, event: UpcomingEvent): string {\r\n return event?.eventId ?? `${index}`;\r\n }\r\n\r\n /**\r\n * Toggles the section's expanded/collapsed state, inverting the card-list\r\n * visibility and the exposed `aria-expanded` value (Req 5.4, 14.3).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onToggleExpanded(): void {\r\n this.isExpanded = !this.isExpanded;\r\n this.expandedChange.emit(this.isExpanded);\r\n }\r\n\r\n /**\r\n * Handles the \"View All\" link, emitting the `viewAll` intent to the host (Req 5.2).\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onViewAll(): void {\r\n this.viewAll.emit();\r\n }\r\n\r\n /**\r\n * Bubbles a card's \"View Event\" activation upward (Req 6.4).\r\n * @param {string} eventId - The event id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onViewEvent(eventId: string): void {\r\n this.viewEvent.emit(eventId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's meeting-name link activation upward (Req 7.4).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.openMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's log-attendance request upward (Req 7.7).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.logAttendance.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Bubbles a card's leave-meeting request upward (Req 7.8).\r\n * @param {string} meetingId - The meeting id emitted by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.leaveMeeting.emit(meetingId);\r\n }\r\n\r\n /**\r\n * Maps a card's `pageChange` into a `meetingPageChange` tagged with the\r\n * originating event id so the host can page the correct event (Req 6.9).\r\n * @param {string} eventId - The id of the event whose card paginated.\r\n * @param {PageChange} page - The requested page from the card paginator.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onMeetingPageChange(eventId: string, page: PageChange): void {\r\n this.meetingPageChange.emit({ eventId, ...page });\r\n }\r\n\r\n /**\r\n * Bubbles a card's lazy child-meeting load request upward, tagged with the\r\n * originating event id so the container can fetch that event's meetings.\r\n * @param {string} eventId - The event whose meetings to load.\r\n * @param {number} page - The one-based page requested by the card.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onLoadEventMeetings(eventId: string, request: { page: number; size: number }): void {\r\n this.loadEventMeetings.emit({ eventId, page: request.page, size: request.size });\r\n }\r\n\r\n /**\r\n * Bubbles a card's navigate-to-meeting request upward unchanged.\r\n * @param {{ eventId: string; meetingId: string }} request - The meeting identity.\r\n * @memberof UpcomingMeetingsEventsComponent\r\n */\r\n onNavigateToMeeting(request: {\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }): void {\r\n this.navigateToMeeting.emit(request);\r\n }\r\n}\r\n","<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 <!-- Collapsed summary: events / meetings / open-for-attendance counts.\r\n The open-for-attendance segment is green bold per Figma. -->\r\n <p\r\n *ngIf=\"!isExpanded && sectionState === sectionStates.LOADED\"\r\n class=\"ieeesa-upcoming-meetings-events__summary\"\r\n >\r\n {{ eventCount }} events · {{ totalMeetingCount }} meetings ·\r\n <span class=\"ieeesa-upcoming-meetings-events__summary-open\">\r\n {{ totalOpenForAttendanceCount }} open for attendance\r\n </span>\r\n </p>\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 (navigateToMeeting)=\"onNavigateToMeeting($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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * Identifies which dashboard section a \"Jump to\" shortcut targets, emitted via\r\n * {@link DashboardWelcomeHeaderComponent.shortcutSelected} for the host/container\r\n * to scroll to or navigate.\r\n */\r\n// eslint-disable-next-line no-unused-vars\r\nexport enum DashboardJumpTarget {\r\n // eslint-disable-next-line no-unused-vars\r\n MEETINGS = 'MEETINGS',\r\n // eslint-disable-next-line no-unused-vars\r\n GROUPS = 'GROUPS',\r\n}\r\n\r\n/**\r\n * A single \"Jump to\" shortcut rendered in the welcome header: a circular icon\r\n * that expands on hover/focus into a pill showing the section label and its\r\n * count badge.\r\n */\r\ninterface JumpShortcut {\r\n target: DashboardJumpTarget;\r\n label: string;\r\n iconUrl: string;\r\n ariaLabel: string;\r\n count: number;\r\n}\r\n\r\n/**\r\n * Welcome_Header renders the personalized greeting and the \"Jump to\" shortcut\r\n * control at the top of the dashboard.\r\n *\r\n * The greeting is composed from the greeting label in `constants.json` and the\r\n * supplied `userName`, falling back to the configured fallback greeting when the\r\n * name is empty or undefined. The \"Jump to\" control shows one circular icon per\r\n * dashboard section (Upcoming Meetings & Events, Your Groups); hovering or\r\n * focusing an icon expands it into a pill with the section label and a count\r\n * badge (the counts are supplied by the host via `meetingsCount` /\r\n * `groupsCount`). Activating a shortcut emits {@link shortcutSelected} with the\r\n * target section for the host to act on. Purely presentational — no API work.\r\n * @export\r\n * @class DashboardWelcomeHeaderComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-dashboard-welcome-header',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './dashboard-welcome-header.component.html',\r\n styleUrls: ['./dashboard-welcome-header.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class DashboardWelcomeHeaderComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private readonly constants: any = constants;\r\n /** User-facing strings sourced from `constants.json`. */\r\n readonly texts = this.constants?.welcomeHeader;\r\n\r\n /** Enum reference for template comparisons. */\r\n readonly jumpTarget = DashboardJumpTarget;\r\n\r\n private userNameValue = '';\r\n /**\r\n * The signed-in user's display name. Drives the personalized greeting; when\r\n * empty or undefined the greeting falls back to the configured fallback text.\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n @Input()\r\n set userName(value: string) {\r\n this.userNameValue = value ?? '';\r\n }\r\n get userName(): string {\r\n return this.userNameValue;\r\n }\r\n\r\n private meetingsCountValue = 0;\r\n /** Count shown in the Upcoming Meetings & Events shortcut badge. */\r\n @Input()\r\n set meetingsCount(value: number) {\r\n this.meetingsCountValue = value ?? 0;\r\n this.buildShortcuts();\r\n }\r\n get meetingsCount(): number {\r\n return this.meetingsCountValue;\r\n }\r\n\r\n private groupsCountValue = 0;\r\n /** Count shown in the Your Groups shortcut badge. */\r\n @Input()\r\n set groupsCount(value: number) {\r\n this.groupsCountValue = value ?? 0;\r\n this.buildShortcuts();\r\n }\r\n get groupsCount(): number {\r\n return this.groupsCountValue;\r\n }\r\n\r\n /** Emits the selected \"Jump to\" target for the host to act on. */\r\n @Output() shortcutSelected = new EventEmitter<DashboardJumpTarget>();\r\n\r\n /** The jump shortcuts rendered in the control, rebuilt when counts change. */\r\n shortcuts: JumpShortcut[] = this.buildShortcutList();\r\n\r\n /**\r\n * The personalized greeting: the greeting label plus the user's name when\r\n * present, otherwise the configured fallback greeting.\r\n * @readonly\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n get greeting(): string {\r\n const name = this.userName?.trim();\r\n return name\r\n ? `${this.texts?.greeting}${name}!`\r\n : `${this.texts?.fallbackGreeting}!`;\r\n }\r\n\r\n /**\r\n * Emits the chosen shortcut's target for the host to scroll/navigate to.\r\n * @param {DashboardJumpTarget} target - The selected section.\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n onShortcutClick(target: DashboardJumpTarget): void {\r\n this.shortcutSelected.emit(target);\r\n }\r\n\r\n /**\r\n * TrackBy for the shortcut list.\r\n * @param {number} _index\r\n * @param {JumpShortcut} shortcut\r\n * @return {string}\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n trackByTarget(_index: number, shortcut: JumpShortcut): string {\r\n return shortcut.target;\r\n }\r\n\r\n /** Rebuilds the shortcut list so the template reflects the latest counts. */\r\n private buildShortcuts(): void {\r\n this.shortcuts = this.buildShortcutList();\r\n }\r\n\r\n /**\r\n * Builds the shortcut view models from `constants.json` and the current\r\n * counts.\r\n * @return {JumpShortcut[]}\r\n * @memberof DashboardWelcomeHeaderComponent\r\n */\r\n private buildShortcutList(): JumpShortcut[] {\r\n const shortcutTexts = this.constants?.welcomeHeader?.shortcuts;\r\n return [\r\n {\r\n target: DashboardJumpTarget.MEETINGS,\r\n label: shortcutTexts?.meetings?.label,\r\n iconUrl: shortcutTexts?.meetings?.iconUrl,\r\n ariaLabel: shortcutTexts?.meetings?.ariaLabel,\r\n count: this.meetingsCountValue,\r\n },\r\n {\r\n target: DashboardJumpTarget.GROUPS,\r\n label: shortcutTexts?.groups?.label,\r\n iconUrl: shortcutTexts?.groups?.iconUrl,\r\n ariaLabel: shortcutTexts?.groups?.ariaLabel,\r\n count: this.groupsCountValue,\r\n },\r\n ];\r\n }\r\n}\r\n","<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","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n Input,\r\n Output,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\r\nimport {\r\n IconButton,\r\n IconButtonComponent,\r\n LoaderComponent,\r\n} from '@ieeesa-npm/presentation';\r\nimport { DashboardSectionState } from '../../models/dashboard-section-state.model';\r\nimport {\r\n GroupHierarchyNode,\r\n GroupRow,\r\n} from '../../models/group-row.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * A single rendered table row. Either a top-level group row (`kind: 'group'`,\r\n * carrying the full {@link GroupRow}) or a hierarchy node row (`kind:\r\n * 'hierarchy'`) revealed step-by-step as the user drills down. `nodeIndex` is\r\n * the node's position in the group's `hierarchy[]`, used to drive the next\r\n * drill-down level and the per-node toggle (matching the Groups module, where\r\n * each level reveals only its next child and that child carries its own +/−).\r\n */\r\ninterface TableRow {\r\n kind: 'group' | 'hierarchy';\r\n group?: GroupRow;\r\n node?: GroupHierarchyNode;\r\n /** Index of this node within the group's hierarchy[] (hierarchy rows only). */\r\n nodeIndex?: number;\r\n level: number;\r\n}\r\n\r\n/**\r\n * Groups_Section (`ieeesa-your-groups`) renders the signed-in user's groups in\r\n * a collapsible card as a custom hierarchy table styled like the My Profile\r\n * Find Groups tree: each group row carries a blue +/- toggle (when it has an\r\n * ancestor hierarchy) that expands to reveal the group's hierarchy path\r\n * (root→leaf), indented. Columns: Group, Type, Officer Role, Affiliation,\r\n * Member Level (the member level renders as a coloured pill — green for an\r\n * assigned level, amber for \"Unassigned\"). The card paginates the top-level\r\n * groups (5 per page).\r\n *\r\n * Purely presentational: data arrives via `@Input`, intents leave via\r\n * `@Output`; no API or navigation here. States (loader / empty / error / table)\r\n * are driven by `sectionState`.\r\n * @export\r\n * @class YourGroupsComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-your-groups',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatPaginatorModule,\r\n LoaderComponent,\r\n IconButtonComponent,\r\n ],\r\n templateUrl: './your-groups.component.html',\r\n styleUrls: ['./your-groups.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class YourGroupsComponent {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private readonly constants: any = constants;\r\n /** User-facing strings sourced from `constants.json`. */\r\n readonly texts = this.constants?.groupsSection;\r\n\r\n /** Enum reference for template comparisons against `sectionState`. */\r\n readonly sectionStates = DashboardSectionState;\r\n\r\n /** Per-level indentation step (px) for the expanded hierarchy rows. */\r\n readonly indentPerLevel = 28;\r\n\r\n /** Selectable \"Items per page\" page sizes. */\r\n readonly pageSizeOptions: number[] = [5, 10, 25];\r\n\r\n /**\r\n * Expand (+) icon button — the SAME sprite icon the Groups package uses for\r\n * its tree expand toggle (icon-expand-collapse-plus), rendered via the shared\r\n * IconButtonComponent for a consistent look across the app.\r\n */\r\n readonly expandIconButton: IconButton = {\r\n id: 1,\r\n iconURL: 'assets/images/sprites/sprites.svg#icon-expand-collapse-plus',\r\n ariaLabel: 'Expand group',\r\n toolTip: 'Expand group',\r\n };\r\n\r\n /** Collapse (−) icon button — the Groups package's icon-expand-collapse-minus. */\r\n readonly collapseIconButton: IconButton = {\r\n id: 2,\r\n iconURL: 'assets/images/sprites/sprites.svg#icon-expand-collapse-minus',\r\n ariaLabel: 'Collapse group',\r\n toolTip: 'Collapse group',\r\n };\r\n\r\n /**\r\n * Returns the +/- toggle icon button for a level, matching the Groups tree:\r\n * the minus (collapse) icon when that level is expanded, otherwise the plus\r\n * (expand) icon.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @return {IconButton}\r\n * @memberof YourGroupsComponent\r\n */\r\n getToggleButton(group: GroupRow, index: number): IconButton {\r\n const button = this.isLevelExpanded(group, index)\r\n ? this.collapseIconButton\r\n : this.expandIconButton;\r\n // Include the target's name so each toggle has a distinct accessible name\r\n // (e.g. \"Expand group Tech working\"). Return a NEW object so the shared\r\n // expand/collapse configs are never mutated.\r\n const name =\r\n index < 0\r\n ? group.group\r\n : group.hierarchy?.[index]?.groupName ?? group.group;\r\n return { ...button, ariaLabel: `${button.ariaLabel} ${name}` };\r\n }\r\n\r\n private groupsValue: GroupRow[] = [];\r\n /** The groups rendered in the table. */\r\n @Input()\r\n set groups(value: GroupRow[]) {\r\n this.groupsValue = value ?? [];\r\n this.rebuildRows();\r\n }\r\n get groups(): GroupRow[] {\r\n return this.groupsValue;\r\n }\r\n\r\n /** The section's load/empty/error state driving the mutually-exclusive regions. */\r\n @Input() sectionState: DashboardSectionState = DashboardSectionState.LOADED;\r\n\r\n /** Total number of groups (for the \"{n} Groups\" count and paginator). */\r\n @Input() totalGroups = 0;\r\n\r\n private pageIndexValue = 0;\r\n /** Current zero-based page index. */\r\n @Input()\r\n set pageIndex(value: number) {\r\n this.pageIndexValue = value ?? 0;\r\n this.rebuildRows();\r\n }\r\n get pageIndex(): number {\r\n return this.pageIndexValue;\r\n }\r\n\r\n private pageSizeValue = 5;\r\n /** Current page size (defaults to 5 rows per page per the design). */\r\n @Input()\r\n set pageSize(value: number) {\r\n this.pageSizeValue = value ?? 5;\r\n this.rebuildRows();\r\n }\r\n get pageSize(): number {\r\n return this.pageSizeValue;\r\n }\r\n\r\n /** Emits when the \"View All\" link is activated. */\r\n @Output() viewAllGroups = new EventEmitter<void>();\r\n\r\n /** Emits the requested page when the paginator changes. */\r\n @Output() pageChange = new EventEmitter<PageChange>();\r\n\r\n /**\r\n * Emits the new expanded state whenever the user toggles the card, so a\r\n * two-way `[(expanded)]` binding keeps the host's flag in sync. Without this,\r\n * a host that opened the card (expanded=true) and then the user collapsing it\r\n * would leave the host flag stale, so re-opening via the same input value\r\n * would be a no-op.\r\n * @memberof YourGroupsComponent\r\n */\r\n @Output() expandedChange = new EventEmitter<boolean>();\r\n\r\n /** Whether the card is expanded (table visible). Starts collapsed. */\r\n isExpanded = false;\r\n\r\n /**\r\n * Allows the host/container to open or close the card (e.g. a \"Jump to\"\r\n * shortcut opens it).\r\n * @memberof YourGroupsComponent\r\n */\r\n @Input()\r\n set expanded(value: boolean) {\r\n this.isExpanded = !!value;\r\n }\r\n get expanded(): boolean {\r\n return this.isExpanded;\r\n }\r\n\r\n /**\r\n * Keys of the hierarchy levels currently expanded, each `\"<groupId>:<index>\"`.\r\n * Index -1 is the group row itself (its toggle reveals the first hierarchy\r\n * node); index N is the Nth hierarchy node (its toggle reveals node N+1). A\r\n * level only reveals the NEXT node, matching the Groups module's step-by-step\r\n * drill-down.\r\n */\r\n private readonly expandedKeys = new Set<string>();\r\n\r\n /** The flattened rows currently rendered (group rows + any revealed hierarchy rows). */\r\n visibleRows: TableRow[] = [];\r\n\r\n /**\r\n * The count shown in the header subtitle — the server total when provided,\r\n * otherwise the number of groups.\r\n * @readonly\r\n * @memberof YourGroupsComponent\r\n */\r\n get groupCount(): number {\r\n return this.totalGroups || this.groups.length || 0;\r\n }\r\n\r\n /**\r\n * Builds the expand/collapse key for a hierarchy level. Index -1 is the group\r\n * row itself; index N is the Nth hierarchy node.\r\n * @param {GroupRow} group\r\n * @param {number} index\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n private levelKey(group: GroupRow, index: number): string {\r\n return `${group.groupId}:${index}`;\r\n }\r\n\r\n /**\r\n * Whether a level shows a +/- toggle.\r\n *\r\n * - Group row (index -1): expandable when it has ANY hierarchy node, matching\r\n * the Groups module which shows the toggle on every group that has related\r\n * hierarchy (driven by hasChildren, true for all these groups).\r\n * - Hierarchy node (index N): expandable only when there is a further node\r\n * after it (step-by-step drill-down); the deepest node is a leaf, no toggle.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n isLevelExpandable(group: GroupRow, index: number): boolean {\r\n const length = group?.hierarchy?.length ?? 0;\r\n if (index < 0) {\r\n // Group row: a toggle only when it has RELATED groups to show — i.e. the\r\n // hierarchy has more than just the group's own node. A single-node\r\n // hierarchy (only itself) has nothing to reveal, so no toggle.\r\n return length > 1;\r\n }\r\n // Hierarchy node: expandable only if a deeper node follows it.\r\n return index < length - 1;\r\n }\r\n\r\n /**\r\n * Whether the group row shows a toggle (has related hierarchy to drill into).\r\n * @param {GroupRow} group\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n hasHierarchy(group: GroupRow): boolean {\r\n return (group?.hierarchy?.length ?? 0) > 1;\r\n }\r\n\r\n /**\r\n * Whether a given level is currently expanded (its next node is revealed).\r\n * @param {GroupRow} group\r\n * @param {number} index\r\n * @return {boolean}\r\n * @memberof YourGroupsComponent\r\n */\r\n isLevelExpanded(group: GroupRow, index: number): boolean {\r\n return this.expandedKeys.has(this.levelKey(group, index));\r\n }\r\n\r\n /** Convenience for the group row (level -1). */\r\n isGroupExpanded(group: GroupRow): boolean {\r\n return this.isLevelExpanded(group, -1);\r\n }\r\n\r\n /**\r\n * Toggles a level's expansion (reveals/hides its next node). Collapsing a\r\n * level also collapses everything deeper under it so re-opening starts fresh.\r\n * @param {GroupRow} group\r\n * @param {number} index - -1 for the group row, else the node index.\r\n * @memberof YourGroupsComponent\r\n */\r\n onToggleLevel(group: GroupRow, index: number): void {\r\n if (!this.isLevelExpandable(group, index)) {\r\n return;\r\n }\r\n const key = this.levelKey(group, index);\r\n if (this.expandedKeys.has(key)) {\r\n // Collapse this level and any deeper levels of the same group.\r\n const length = group?.hierarchy?.length ?? 0;\r\n for (let deeper = index; deeper < length; deeper++) {\r\n this.expandedKeys.delete(this.levelKey(group, deeper));\r\n }\r\n } else {\r\n this.expandedKeys.add(key);\r\n }\r\n this.rebuildRows();\r\n }\r\n\r\n /**\r\n * Toggles the card's expanded/collapsed state (whole table visibility) and\r\n * emits the new state so the host's two-way binding stays in sync.\r\n * @memberof YourGroupsComponent\r\n */\r\n onToggleExpand(): void {\r\n this.isExpanded = !this.isExpanded;\r\n this.expandedChange.emit(this.isExpanded);\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" intent for the host.\r\n * @memberof YourGroupsComponent\r\n */\r\n onViewAll(): void {\r\n this.viewAllGroups.emit();\r\n }\r\n\r\n /**\r\n * Re-emits the Material paginator change (page index or \"Items per page\"\r\n * size) as a {@link PageChange} for the host.\r\n * @param {PageEvent} event - The Material paginator event.\r\n * @memberof YourGroupsComponent\r\n */\r\n onPaginatorChange(event: PageEvent): void {\r\n this.pageChange.emit({\r\n pageIndex: event.pageIndex,\r\n pageSize: event.pageSize,\r\n });\r\n }\r\n\r\n /**\r\n * Resolves the member-level pill CSS class, mirroring the My Groups profile\r\n * tab: an assigned level renders green (success), \"Unassigned\" renders amber.\r\n * @param {string} memberLevel\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n resolveBadgeClass(memberLevel: string): string {\r\n const badge = this.texts?.memberLevelBadge;\r\n return memberLevel === this.texts?.unassignedMemberLevel\r\n ? badge?.warning\r\n : badge?.success;\r\n }\r\n\r\n /**\r\n * TrackBy for the rendered table rows.\r\n * @param {number} index\r\n * @param {TableRow} row\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n trackByRow(index: number, row: TableRow): string {\r\n return row.kind === 'group'\r\n ? `g:${row.group?.groupId}`\r\n : `h:${row.group?.groupId}:${row.node?.groupId}:${index}`;\r\n }\r\n\r\n /**\r\n * Rebuilds the visible rows for the current page. Each group reveals its\r\n * hierarchy ONE level at a time (Groups-module style): the group row reveals\r\n * node 0 only when its own level (-1) is expanded; node 0 reveals node 1 only\r\n * when node 0's level is expanded; and so on. Each revealed node that still\r\n * has a child carries its own +/- toggle.\r\n * @memberof YourGroupsComponent\r\n */\r\n private rebuildRows(): void {\r\n const start = this.pageIndex * this.pageSize;\r\n const pageGroups = this.groups.slice(start, start + this.pageSize);\r\n const rows: TableRow[] = [];\r\n\r\n pageGroups.forEach((group) => {\r\n rows.push({ kind: 'group', group, level: 0 });\r\n\r\n const hierarchy = group.hierarchy ?? [];\r\n // Walk the path, revealing each next node only while the chain of\r\n // parent levels above it stays expanded. Stop as soon as a level is\r\n // collapsed.\r\n for (let index = 0; index < hierarchy.length; index++) {\r\n if (!this.isLevelExpanded(group, index - 1)) {\r\n break;\r\n }\r\n rows.push({\r\n kind: 'hierarchy',\r\n group,\r\n node: hierarchy[index],\r\n nodeIndex: index,\r\n level: index + 1,\r\n });\r\n }\r\n });\r\n\r\n this.visibleRows = rows;\r\n }\r\n}\r\n","<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 <!-- Group row toggle (level -1): reveals the first hierarchy\r\n node. Same shared icon button as the Groups tree. -->\r\n <ieeesa-icon-button\r\n *ngIf=\"isLevelExpandable(row.group!, -1)\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [iconButton]=\"getToggleButton(row.group!, -1)\"\r\n [ariaExpanded]=\"isLevelExpanded(row.group!, -1)\"\r\n (iconButtonClick)=\"onToggleLevel(row.group!, -1)\"\r\n ></ieeesa-icon-button>\r\n <!-- Leaf group (no hierarchy): spacer keeps names aligned. -->\r\n <span\r\n *ngIf=\"!isLevelExpandable(row.group!, -1)\"\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 <!-- This node's own +/- toggle, when it has a further child to\r\n reveal (step-by-step drill-down like the Groups tree). -->\r\n <ieeesa-icon-button\r\n *ngIf=\"isLevelExpandable(row.group!, row.nodeIndex!)\"\r\n class=\"ieeesa-your-groups__hierarchy-toggle\"\r\n [iconButton]=\"getToggleButton(row.group!, row.nodeIndex!)\"\r\n [ariaExpanded]=\"isLevelExpanded(row.group!, row.nodeIndex!)\"\r\n (iconButtonClick)=\"onToggleLevel(row.group!, row.nodeIndex!)\"\r\n ></ieeesa-icon-button>\r\n <!-- Leaf node: spacer keeps the name aligned with parent nodes\r\n (same footprint as the toggle), no connector arrow. -->\r\n <span\r\n *ngIf=\"!isLevelExpandable(row.group!, row.nodeIndex!)\"\r\n class=\"ieeesa-your-groups__toggle-spacer\"\r\n aria-hidden=\"true\"\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 — 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","/**\r\n * Pure mappers converting the raw \"home\" events-&-meetings backend list/detail\r\n * items into the dashboard view models. No Angular / service dependencies so\r\n * they are trivially unit-testable and shared by {@link DashboardService}.\r\n *\r\n * Backend dates are ISO-8601 strings; callers format them with luxon at render\r\n * time. The list mapper enforces the dashboard rule that STANDALONE_MEETING rows\r\n * always sort LAST within the section.\r\n */\r\nimport { AttendanceState } from '../models/attendance-state.model';\r\nimport {\r\n EventMeetingDetailItem,\r\n EventMeetingListItem,\r\n} from '../models/event-meeting-list-item.model';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\n\r\n/**\r\n * Determines whether a raw list item is an EVENT (owns child meetings) or a\r\n * STANDALONE_MEETING, using the backend `isMeetingEvent` discriminator (falling\r\n * back to `hasChildren`).\r\n * @param {EventMeetingListItem} item - The raw list item.\r\n * @return {UpcomingItemKind} The resolved render kind.\r\n */\r\nexport function resolveItemKind(\r\n item: EventMeetingListItem\r\n): UpcomingItemKind {\r\n const isEvent = item?.isMeetingEvent === true || item?.hasChildren === true;\r\n return isEvent ? UpcomingItemKind.EVENT : UpcomingItemKind.STANDALONE_MEETING;\r\n}\r\n\r\n/**\r\n * Maps a raw backend list item to the {@link UpcomingEvent} view model. EVENT\r\n * rows carry their total / open-for-attendance counts and start with an empty\r\n * `meetings` array (child meetings are lazily loaded on drill-down);\r\n * STANDALONE_MEETING rows carry their own group/location + attendance state.\r\n * @param {EventMeetingListItem} item - The raw list item.\r\n * @return {UpcomingEvent} The mapped view model.\r\n */\r\nexport function mapListItemToUpcomingEvent(\r\n item: EventMeetingListItem\r\n): UpcomingEvent {\r\n const kind = resolveItemKind(item);\r\n const isEvent = kind === UpcomingItemKind.EVENT;\r\n return {\r\n eventId: item?.id ?? '',\r\n kind,\r\n title: item?.name ?? '',\r\n status: item?.status ?? '',\r\n // The list endpoint has no day indicator; it is populated on drill-down\r\n // from the event's currentDay / totalDays.\r\n dayIndicator: '',\r\n meetingCount: isEvent ? item?.totalMeetingCount ?? 0 : 1,\r\n openForAttendanceCount: isEvent\r\n ? item?.meetingsOpenForAttendanceCount ?? 0\r\n : 0,\r\n startDateTime: item?.startDateTime,\r\n endDateTime: item?.endDateTime,\r\n timezone: item?.timeZone ?? '',\r\n groupOrCommittee: item?.groupName ?? item?.groupAcronym ?? '',\r\n roomOrLocation: item?.meetingLocation ?? '',\r\n attendanceState: isEvent ? undefined : item?.attendanceState,\r\n meetings: [],\r\n };\r\n}\r\n\r\n/**\r\n * Maps a raw backend combined list into the dashboard view models, enforcing\r\n * that STANDALONE_MEETING rows always sort LAST while preserving the backend's\r\n * within-group ordering for each partition (stable sort).\r\n * @param {EventMeetingListItem[]} items - The raw list items.\r\n * @return {UpcomingEvent[]} The mapped, standalone-last ordered view models.\r\n */\r\nexport function mapEventMeetingList(\r\n items: EventMeetingListItem[]\r\n): UpcomingEvent[] {\r\n const mapped = (items ?? []).map((item) => mapListItemToUpcomingEvent(item));\r\n const events = mapped.filter(\r\n (entry) => entry.kind === UpcomingItemKind.EVENT\r\n );\r\n const standalone = mapped.filter(\r\n (entry) => entry.kind === UpcomingItemKind.STANDALONE_MEETING\r\n );\r\n return [...events, ...standalone];\r\n}\r\n\r\n/**\r\n * Maps a raw backend drill-down meeting item to the {@link MeetingRow} view\r\n * model used by the event block's expanded meeting list.\r\n * @param {EventMeetingDetailItem} item - The raw child-meeting item.\r\n * @param {string} [eventId] - The owning event id (for navigation).\r\n * @return {MeetingRow} The mapped meeting row.\r\n */\r\nexport function mapDetailItemToMeetingRow(\r\n item: EventMeetingDetailItem,\r\n eventId = ''\r\n): MeetingRow {\r\n const status = item?.status ?? '';\r\n const attendanceState =\r\n item?.attendanceState ?? AttendanceState.NOT_ATTENDING;\r\n return {\r\n meetingId: item?.meetingId ?? '',\r\n eventId,\r\n meetingName: item?.meetingTitle ?? '',\r\n groupOrCommittee: item?.groupName ?? item?.groupAcronym ?? '',\r\n roomOrLocation: item?.location ?? '',\r\n startDateTime: item?.meetingStDate,\r\n endDateTime: item?.meetingEdDate,\r\n timezone: item?.timeZone ?? '',\r\n status,\r\n attendanceState,\r\n isOpenForAttendance: status.trim().toLowerCase() === 'in progress',\r\n };\r\n}\r\n\r\n/**\r\n * Maps a raw backend drill-down meeting list to {@link MeetingRow} view models,\r\n * tagging each with its owning event id for navigation.\r\n * @param {EventMeetingDetailItem[]} items - The raw child-meeting items.\r\n * @param {string} [eventId] - The owning event id.\r\n * @return {MeetingRow[]} The mapped meeting rows.\r\n */\r\nexport function mapEventMeetingDetails(\r\n items: EventMeetingDetailItem[],\r\n eventId = ''\r\n): MeetingRow[] {\r\n return (items ?? []).map((item) =>\r\n mapDetailItemToMeetingRow(item, eventId)\r\n );\r\n}\r\n","import { AttendanceState } from '../models/attendance-state.model';\r\n\r\n/**\r\n * Pure reducers for the dashboard attendance state. These functions never\r\n * mutate their inputs; each returns a new object/set so they can be exercised\r\n * directly by property tests and composed by the DashboardService.\r\n */\r\n\r\n/**\r\n * Produce a new attendance-state map with the target meeting set to\r\n * CURRENTLY_ATTENDING. Every other entry is copied unchanged (frame property).\r\n *\r\n * @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).\r\n * @param {string} meetingId The meeting whose state transitions to CURRENTLY_ATTENDING.\r\n * @return {Record<string, AttendanceState>} A new map reflecting the successful log-attendance action.\r\n */\r\nexport const applyLogAttendanceSuccess = (\r\n map: Record<string, AttendanceState>,\r\n meetingId: string\r\n): Record<string, AttendanceState> => ({\r\n ...map,\r\n [meetingId]: AttendanceState.CURRENTLY_ATTENDING,\r\n});\r\n\r\n/**\r\n * Produce a new attendance-state map with the target meeting set to\r\n * NOT_ATTENDING. Every other entry is copied unchanged (frame property).\r\n *\r\n * @param {Record<string, AttendanceState>} map The current attendance-state map (not mutated).\r\n * @param {string} meetingId The meeting whose state transitions to NOT_ATTENDING.\r\n * @return {Record<string, AttendanceState>} A new map reflecting the successful leave-meeting action.\r\n */\r\nexport const applyLeaveMeetingSuccess = (\r\n map: Record<string, AttendanceState>,\r\n meetingId: string\r\n): Record<string, AttendanceState> => ({\r\n ...map,\r\n [meetingId]: AttendanceState.NOT_ATTENDING,\r\n});\r\n\r\n/**\r\n * Add a meeting to the in-flight set, returning a new set. Prior membership is\r\n * retained so the displayed attendance state is preserved while the request\r\n * resolves.\r\n *\r\n * @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).\r\n * @param {string} meetingId The meeting whose attendance action has started.\r\n * @return {Set<string>} A new set that additionally contains the meeting id.\r\n */\r\nexport const beginAttendanceAction = (\r\n set: ReadonlySet<string>,\r\n meetingId: string\r\n): Set<string> => new Set([...set, meetingId]);\r\n\r\n/**\r\n * Remove a meeting from the in-flight set, returning a new set. All other\r\n * in-flight ids are retained.\r\n *\r\n * @param {ReadonlySet<string>} set The current in-flight meeting-id set (not mutated).\r\n * @param {string} meetingId The meeting whose attendance action has resolved.\r\n * @return {Set<string>} A new set that no longer contains the meeting id.\r\n */\r\nexport const endAttendanceAction = (\r\n set: ReadonlySet<string>,\r\n meetingId: string\r\n): Set<string> => {\r\n const next = new Set(set);\r\n next.delete(meetingId);\r\n return next;\r\n};\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n BehaviorSubject,\r\n Observable,\r\n catchError,\r\n map,\r\n} from 'rxjs';\r\nimport { HttpService } from '@ieeesa-npm/utility';\r\nimport { UserPermission } from '@ieeesa-npm/models';\r\nimport { AttendanceState } from '../models/attendance-state.model';\r\nimport { DashboardListResponse } from '../models/dashboard-list-response.model';\r\nimport { DashboardSectionState } from '../models/dashboard-section-state.model';\r\nimport { GroupRow } from '../models/group-row.model';\r\nimport {\r\n MyGroupsView,\r\n MyGroupView,\r\n} from '../models/my-groups-view.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\nimport {\r\n EventMeetingDetailPayload,\r\n EventMeetingListPayload,\r\n} from '../models/event-meeting-list-payload.model';\r\nimport {\r\n EventMeetingDetailBody,\r\n EventMeetingDetailResponse,\r\n EventMeetingListResponse,\r\n} from '../models/event-meeting-list-item.model';\r\nimport {\r\n mapEventMeetingDetails,\r\n mapEventMeetingList,\r\n} from '../utils/event-meeting-mapper.util';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\n\r\n/** Fallback label for an empty group type / member level, matching the My Groups tab. */\r\nconst UNASSIGNED_LABEL = 'Unassigned';\r\n/** Placeholder for an empty cell value. */\r\nconst EMPTY_VALUE = '-';\r\n/** Default page size for the top-level home events-&-meetings list. */\r\nconst UPCOMING_PAGE_SIZE = 10;\r\n/** Default page size for an event's drill-down child-meeting list. */\r\nconst EVENT_MEETINGS_PAGE_SIZE = 5;\r\nimport {\r\n applyLeaveMeetingSuccess,\r\n applyLogAttendanceSuccess,\r\n beginAttendanceAction,\r\n endAttendanceAction,\r\n} from './attendance-reducers';\r\n\r\n/**\r\n * DashboardService is the single source of truth for the dashboard landing\r\n * page's data and attendance state. It mirrors the `events-and-meetings`\r\n * service conventions: it is a `providedIn: 'root'` singleton, holds the host\r\n * `apiBaseUrl` / `userPermissions` set via {@link setAppConfig}, owns its state\r\n * via `BehaviorSubject`s exposed as observables, and reaches the backend only\r\n * through the shared `HttpService` from `@ieeesa-npm/utility` (never\r\n * `HttpClient` directly).\r\n *\r\n * The upcoming-events load calls the real `POST /meetings/eventsAndMeetings`\r\n * endpoint (child meetings are lazily loaded per-event via\r\n * `POST /meetings/meetingsDetails`); the groups load calls `GET\r\n * /groups/my-groups`. The attendance actions compose the pure reducers from\r\n * `attendance-reducers.ts` so the displayed `AttendanceState` only advances on a\r\n * successful resolution and the prior state is retained on failure.\r\n * @export\r\n * @class DashboardService\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class DashboardService {\r\n apiBaseUrl!: string;\r\n userPermissions!: UserPermission[];\r\n\r\n private readonly upcomingEvents = new BehaviorSubject<UpcomingEvent[]>([]);\r\n private readonly groups = new BehaviorSubject<GroupRow[]>([]);\r\n private readonly upcomingState = new BehaviorSubject<DashboardSectionState>(\r\n DashboardSectionState.LOADING\r\n );\r\n private readonly groupsState = new BehaviorSubject<DashboardSectionState>(\r\n DashboardSectionState.LOADING\r\n );\r\n private readonly attendanceStates = new BehaviorSubject<\r\n Record<string, AttendanceState>\r\n >({});\r\n private readonly inFlightMeetingIds = new BehaviorSubject<\r\n ReadonlySet<string>\r\n >(new Set<string>());\r\n\r\n /** Emits the list of the user's upcoming events. */\r\n upcomingEvents$: Observable<UpcomingEvent[]> =\r\n this.upcomingEvents.asObservable();\r\n /** Emits the list of the user's groups. */\r\n groups$: Observable<GroupRow[]> = this.groups.asObservable();\r\n /** Emits the load/empty/error state of the upcoming-events section. */\r\n upcomingState$: Observable<DashboardSectionState> =\r\n this.upcomingState.asObservable();\r\n /** Emits the load/empty/error state of the groups section. */\r\n groupsState$: Observable<DashboardSectionState> =\r\n this.groupsState.asObservable();\r\n /** Emits the per-meeting attendance-state map. */\r\n attendanceStates$: Observable<Record<string, AttendanceState>> =\r\n this.attendanceStates.asObservable();\r\n /** Emits the set of meeting ids with an attendance action in flight. */\r\n inFlightMeetingIds$: Observable<ReadonlySet<string>> =\r\n this.inFlightMeetingIds.asObservable();\r\n\r\n constructor(\r\n // eslint-disable-next-line no-unused-vars\r\n private httpService: HttpService // eslint-disable-next-line no-empty-function\r\n ) {}\r\n\r\n /**\r\n * Stores the host-supplied API base URL and user permissions used to build\r\n * request URLs and gate permission-controlled actions. Mirrors the\r\n * `events-and-meetings` service `setAppConfig`.\r\n * @param {string} apiBaseURL - The host application's API base URL.\r\n * @param {UserPermission[]} userPermissions - The signed-in user's permissions.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n setAppConfig(apiBaseURL: string, userPermissions: UserPermission[]): void {\r\n this.apiBaseUrl = apiBaseURL;\r\n this.userPermissions = userPermissions;\r\n }\r\n\r\n /**\r\n * Loads the user's combined upcoming events & standalone meetings from the\r\n * backend via `POST {apiBaseUrl}/meetings/home/eventsAndMeetings`. The response\r\n * (which carries per-event `totalMeetingCount` / `meetingsOpenForAttendanceCount`\r\n * and per-standalone `attendanceState` directly) is mapped into the dashboard\r\n * view models (STANDALONE_MEETING rows ordered last), the per-meeting\r\n * attendance-state map is seeded, and the section advances through\r\n * LOADING → LOADED/EMPTY on success. `appId` is taken from the JWT, so it is\r\n * not sent. Follows the shared `pipe(map, catchError(throw))` pattern.\r\n * @return {Observable<EventMeetingListResponse>} The home events-&-meetings response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadUpcomingEvents(): Observable<EventMeetingListResponse> {\r\n this.upcomingState.next(DashboardSectionState.LOADING);\r\n const payload: EventMeetingListPayload = {\r\n payload: {\r\n page: 1,\r\n size: UPCOMING_PAGE_SIZE,\r\n sortColumn: 'startDateTime',\r\n ascendingOrder: true,\r\n searchTerm: null,\r\n },\r\n };\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/home/eventsAndMeetings`, payload)\r\n .pipe(\r\n map((response: EventMeetingListResponse) => {\r\n const events = mapEventMeetingList(\r\n response?.body?.eventMeetingList ?? []\r\n );\r\n this.upcomingEvents.next(events);\r\n this.seedAttendanceStates(events);\r\n this.upcomingState.next(\r\n events.length > 0\r\n ? DashboardSectionState.LOADED\r\n : DashboardSectionState.EMPTY\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n this.upcomingState.next(DashboardSectionState.ERROR);\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Lazily loads (and paginates) the child meetings of an EVENT via\r\n * `POST {apiBaseUrl}/meetings/home/events/{eventId}/meetings` (the drill-down\r\n * endpoint). The `eventId` is sent in the URL path; only `page` / `size` are\r\n * used in the body. On success the drill-down body (day indicator, counts,\r\n * paginator total, and the paged meetings) is merged onto the matching event,\r\n * and the per-meeting attendance-state map is extended. Each event paginates\r\n * independently.\r\n * @param {string} eventId - The event whose meetings to load.\r\n * @param {number} [page=1] - The one-based page to request.\r\n * @param {number} [size=EVENT_MEETINGS_PAGE_SIZE] - The page size.\r\n * @return {Observable<EventMeetingDetailResponse>} The drill-down response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadEventMeetings(\r\n eventId: string,\r\n page = 1,\r\n size = EVENT_MEETINGS_PAGE_SIZE\r\n ): Observable<EventMeetingDetailResponse> {\r\n const payload: EventMeetingDetailPayload = {\r\n payload: { page, size },\r\n };\r\n return this.httpService\r\n .postData(\r\n `${this.apiBaseUrl}/meetings/home/events/${encodeURIComponent(\r\n eventId\r\n )}/meetings`,\r\n payload\r\n )\r\n .pipe(\r\n map((response: EventMeetingDetailResponse) => {\r\n const body = response?.body;\r\n const meetings = mapEventMeetingDetails(body?.meetings ?? [], eventId);\r\n this.mergeEventMeetings(eventId, meetings, body);\r\n this.seedAttendanceStatesFromMeetings(meetings);\r\n return response;\r\n }),\r\n catchError((error) => {\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Merges a freshly loaded drill-down page onto the matching event in the\r\n * `upcomingEvents` list: the paged `meetings`, the paginator total\r\n * (`totalRecords` = the user's tied upcoming meetings), the event's full\r\n * `totalMeetingCount` / `meetingsOpenForAttendanceCount`, and the\r\n * \"Day X of Y\" indicator derived from `currentDay` / `totalDays`. Leaves all\r\n * other events untouched.\r\n * @param {string} eventId - The event to merge meetings onto.\r\n * @param {MeetingRow[]} meetings - The mapped drill-down meetings for the page.\r\n * @param {EventMeetingDetailBody | undefined} body - The drill-down response body.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private mergeEventMeetings(\r\n eventId: string,\r\n meetings: MeetingRow[],\r\n body: EventMeetingDetailBody | undefined\r\n ): void {\r\n const totalRecords = body?.totalRecords ?? meetings.length;\r\n const totalMeetingCount = body?.totalMeetingCount ?? totalRecords;\r\n const openForAttendanceCount = body?.meetingsOpenForAttendanceCount ?? 0;\r\n const currentDay = body?.currentDay;\r\n const totalDays = body?.totalDays;\r\n const dayIndicator =\r\n currentDay && totalDays ? `Day ${currentDay} of ${totalDays}` : '';\r\n const next = this.upcomingEvents.value.map((event) => {\r\n if (event.eventId !== eventId) {\r\n return event;\r\n }\r\n return {\r\n ...event,\r\n meetings,\r\n // Paginator length = count of the user's tied upcoming meetings.\r\n meetingPageTotal: totalRecords,\r\n meetingCount: totalMeetingCount,\r\n openForAttendanceCount,\r\n dayIndicator: dayIndicator || event.dayIndicator,\r\n };\r\n });\r\n this.upcomingEvents.next(next);\r\n }\r\n\r\n /**\r\n * Loads the user's groups, driving the groups section through\r\n * LOADING → LOADED/EMPTY on success and leaving the caller to set ERROR on\r\n * failure. Follows the `pipe(map, catchError(throw))` pattern.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n * @return {Observable<DashboardListResponse<GroupRow[]>>} The groups response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadGroups(): Observable<DashboardListResponse<MyGroupsView>> {\r\n this.groupsState.next(DashboardSectionState.LOADING);\r\n return this.httpService\r\n .getData(`${this.apiBaseUrl}/groups/my-groups`)\r\n .pipe(\r\n map((response: DashboardListResponse<MyGroupsView>) => {\r\n const groups = (response?.body?.groups ?? []).map((group) =>\r\n this.mapGroup(group)\r\n );\r\n this.groups.next(groups);\r\n this.groupsState.next(\r\n groups.length > 0\r\n ? DashboardSectionState.LOADED\r\n : DashboardSectionState.EMPTY\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n this.groupsState.next(DashboardSectionState.ERROR);\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Maps a backend {@link MyGroupView} to the table-facing {@link GroupRow}.\r\n * Mirrors the My Groups profile tab: the type falls back to \"Unassigned\" when\r\n * `groupTypeName` is null, affiliations are comma-joined, empty officer role /\r\n * affiliation render as a placeholder, and a blank member level becomes\r\n * \"Unassigned\" (rendered as the warning pill by the Your Groups component).\r\n * @param {MyGroupView} group - The backend group view.\r\n * @return {GroupRow}\r\n * @memberof DashboardService\r\n */\r\n private mapGroup(group: MyGroupView): GroupRow {\r\n // The backend returns officer roles as an `officer` array of\r\n // { officerId, officerName }. Join the names for the Officer Role column\r\n // (e.g. \"Chair\" or \"Chair, Vice Chair\"); show the placeholder when empty.\r\n const officerRole =\r\n (group.officer ?? [])\r\n .map((officer) => officer?.officerName?.trim())\r\n .filter((name) => !!name)\r\n .join(', ') || EMPTY_VALUE;\r\n\r\n return {\r\n groupId: group.groupId,\r\n group: group.groupName,\r\n type: group.groupTypeName || group.groupType || UNASSIGNED_LABEL,\r\n officerRole,\r\n affiliation: group.affiliations?.join(', ') || EMPTY_VALUE,\r\n memberLevel: group.memberLevel?.trim() || UNASSIGNED_LABEL,\r\n // Carry the ancestor hierarchy through for the expandable hierarchy rows.\r\n hierarchy: group.hierarchy ?? [],\r\n };\r\n }\r\n\r\n /**\r\n * Logs attendance for a meeting. Marks the meeting in-flight (retaining the\r\n * prior displayed state), posts through `HttpService`, applies the\r\n * log-attendance-success reducer on success, clears the in-flight flag on\r\n * completion, and rethrows while retaining prior state on failure.\r\n * @param {string} meetingId - The meeting to log attendance for.\r\n * @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.\r\n * @memberof DashboardService\r\n */\r\n logAttendance(\r\n meetingId: string\r\n ): Observable<DashboardListResponse<unknown>> {\r\n this.inFlightMeetingIds.next(\r\n beginAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/attendance/log`, { meetingId })\r\n .pipe(\r\n map((response) => {\r\n this.attendanceStates.next(\r\n applyLogAttendanceSuccess(this.attendanceStates.value, meetingId)\r\n );\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n // Retain prior attendance state; only clear the in-flight flag.\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Leaves a meeting. Marks the meeting in-flight (retaining the prior\r\n * displayed state), posts through `HttpService`, applies the\r\n * leave-meeting-success reducer on success, clears the in-flight flag on\r\n * completion, and rethrows while retaining prior state on failure.\r\n * @param {string} meetingId - The meeting to leave.\r\n * @return {Observable<DashboardListResponse<unknown>>} The attendance response envelope.\r\n * @memberof DashboardService\r\n */\r\n leaveMeeting(\r\n meetingId: string\r\n ): Observable<DashboardListResponse<unknown>> {\r\n this.inFlightMeetingIds.next(\r\n beginAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return this.httpService\r\n .postData(`${this.apiBaseUrl}/meetings/attendance/leave`, { meetingId })\r\n .pipe(\r\n map((response) => {\r\n this.attendanceStates.next(\r\n applyLeaveMeetingSuccess(this.attendanceStates.value, meetingId)\r\n );\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n return response;\r\n }),\r\n catchError((error) => {\r\n // Retain prior attendance state; only clear the in-flight flag.\r\n this.inFlightMeetingIds.next(\r\n endAttendanceAction(this.inFlightMeetingIds.value, meetingId)\r\n );\r\n throw error;\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Returns a synchronous snapshot of the per-meeting attendance-state map.\r\n * @return {Record<string, AttendanceState>} The current attendance-state map.\r\n * @memberof DashboardService\r\n */\r\n getAttendanceStatesSnapshot(): Record<string, AttendanceState> {\r\n return this.attendanceStates.value;\r\n }\r\n\r\n /**\r\n * Seeds the attendance-state map from a freshly loaded list of events, using\r\n * each meeting's `attendanceState` (defaulting to `NOT_ATTENDING`). Keeps the\r\n * displayed state in sync with the data load without overwriting ids that are\r\n * not present in the new list.\r\n * @param {UpcomingEvent[]} events - The loaded upcoming events.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private seedAttendanceStates(events: UpcomingEvent[]): void {\r\n const next: Record<string, AttendanceState> = {\r\n ...this.attendanceStates.value,\r\n };\r\n events.forEach((event) => {\r\n // Standalone meetings carry their own attendance state keyed by their id\r\n // (eventId == meetingId for standalone rows).\r\n if (event.kind === UpcomingItemKind.STANDALONE_MEETING && event.eventId) {\r\n next[event.eventId] =\r\n event.attendanceState ?? AttendanceState.NOT_ATTENDING;\r\n }\r\n (event.meetings ?? []).forEach((meeting) => {\r\n if (meeting.meetingId) {\r\n next[meeting.meetingId] =\r\n meeting.attendanceState ?? AttendanceState.NOT_ATTENDING;\r\n }\r\n });\r\n });\r\n this.attendanceStates.next(next);\r\n }\r\n\r\n /**\r\n * Seeds the attendance-state map from a list of meeting rows, using each\r\n * meeting's `attendanceState` (defaulting to `NOT_ATTENDING`) without\r\n * overwriting ids absent from the new list. Shared by the list load and the\r\n * per-event expand so freshly loaded child meetings pick up their state.\r\n * @param {MeetingRow[]} meetings - The meeting rows to seed from.\r\n * @return {void}\r\n * @memberof DashboardService\r\n */\r\n private seedAttendanceStatesFromMeetings(meetings: MeetingRow[]): void {\r\n const next: Record<string, AttendanceState> = {\r\n ...this.attendanceStates.value,\r\n };\r\n meetings.forEach((meeting) => {\r\n if (meeting.meetingId) {\r\n next[meeting.meetingId] =\r\n meeting.attendanceState ??\r\n next[meeting.meetingId] ??\r\n AttendanceState.NOT_ATTENDING;\r\n }\r\n });\r\n this.attendanceStates.next(next);\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { UserPermission } from '@ieeesa-npm/models';\r\nimport { AttendanceActionPermissions } from '../models/attendance-action-permissions.model';\r\n\r\n/**\r\n * Permission display names that gate the dashboard attendance actions. These\r\n * match the local demo mock. The real backend grants attendance capability via\r\n * a permission id (see {@link ATTENDANCE_PERMISSION_IDS}) rather than these\r\n * display names, so both are accepted.\r\n */\r\n/* eslint-disable no-unused-vars */\r\nexport enum DashboardPermissionType {\r\n LOG_ATTENDANCE = 'Log Attendance',\r\n LEAVE_MEETING = 'Leave Meeting',\r\n}\r\n/* eslint-enable no-unused-vars */\r\n\r\n/**\r\n * Real backend permission ids that grant attendance capability. The attendance\r\n * (log / leave) actions on the dashboard are gated by the same permission the\r\n * `events-and-meetings` library uses for attendance — \"View and Export\r\n * Attendance\" (`PERM_SAAPPS_VIEW_EXPORT_ATTENDANCE`).\r\n */\r\nconst ATTENDANCE_PERMISSION_IDS: readonly string[] = [\r\n 'PERM_SAAPPS_VIEW_EXPORT_ATTENDANCE',\r\n];\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class UserPermissionsService {\r\n /**\r\n * Returns access provision for the passed action/feature based on whether the\r\n * signed-in user has an appropriate permission — matched by the legacy display\r\n * name (used by the local demo mock) OR by one of the real backend permission\r\n * ids in {@link ATTENDANCE_PERMISSION_IDS}.\r\n * @param {DashboardPermissionType} permission\r\n * @param {UserPermission[]} userPermissions\r\n * @return {boolean}\r\n * @memberof UserPermissionsService\r\n */\r\n validateAccessPermission(\r\n permission: DashboardPermissionType,\r\n userPermissions: UserPermission[]\r\n ): boolean {\r\n if (!(userPermissions?.length > 0)) {\r\n return false;\r\n }\r\n return userPermissions.some(\r\n ({ permissionName, permissionId }) =>\r\n permissionName === permission ||\r\n ATTENDANCE_PERMISSION_IDS.includes(permissionId)\r\n );\r\n }\r\n\r\n /**\r\n * Maps the host-supplied user permissions to the attendance-action permissions consumed by the dashboard rows.\r\n * @param {UserPermission[]} userPermissions\r\n * @return {AttendanceActionPermissions}\r\n * @memberof UserPermissionsService\r\n */\r\n mapToAttendanceActionPermissions(\r\n userPermissions: UserPermission[]\r\n ): AttendanceActionPermissions {\r\n return {\r\n canLogAttendance: this.validateAccessPermission(\r\n DashboardPermissionType.LOG_ATTENDANCE,\r\n userPermissions\r\n ),\r\n canLeaveMeeting: this.validateAccessPermission(\r\n DashboardPermissionType.LEAVE_MEETING,\r\n userPermissions\r\n ),\r\n };\r\n }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n Output,\r\n ViewChild,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { Subject, takeUntil } from 'rxjs';\r\nimport { BreakpointObserverService } from '@ieeesa-npm/presentation';\r\nimport { AlertType, UserPermission } from '@ieeesa-npm/models';\r\nimport { AlertsService } from '@ieeesa-npm/utility';\r\nimport { AttendanceActionPermissions } from './models/attendance-action-permissions.model';\r\nimport { AttendanceState } from './models/attendance-state.model';\r\nimport { DashboardRouteConfig } from './models/dashboard-route-config.model';\r\nimport { DashboardSectionState } from './models/dashboard-section-state.model';\r\nimport { DashboardUserInfo } from './models/dashboard-user-info.model';\r\nimport { GroupRow } from './models/group-row.model';\r\nimport { PageChange } from './models/page-change.model';\r\nimport { UpcomingEvent } from './models/upcoming-event.model';\r\nimport { DashboardService } from './services/dashboard.service';\r\nimport { UserPermissionsService } from './services/user-permissions.service';\r\nimport { UpcomingMeetingsEventsComponent } from './components/upcoming-meetings-events/upcoming-meetings-events.component';\r\nimport * as constants from './assets/constants.json';\r\nimport {\r\n DashboardJumpTarget,\r\n DashboardWelcomeHeaderComponent,\r\n} from './components/welcome-header/dashboard-welcome-header.component';\r\nimport { YourGroupsComponent } from './components/your-groups/your-groups.component';\r\n\r\n/**\r\n * A navigation intent emitted by {@link DashboardComponent} for the host\r\n * application to act on. The library never performs navigation itself; it emits\r\n * the resolved target `path` (from the {@link DashboardRouteConfig}) together\r\n * with the triggering identifier so the host can route accordingly (Req 11.1).\r\n */\r\nexport interface DashboardNavigationIntent {\r\n /** The resolved target route path from the active {@link DashboardRouteConfig}. */\r\n path: string;\r\n /** The identifier that triggered the navigation (event/meeting/group id), when applicable. */\r\n id?: string;\r\n /** Query params to attach to the navigation (e.g. eventId/meetingId/actionType). */\r\n queryParams?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Dashboard (`ieeesa-dashboard`) is the root container and single host entry\r\n * point for the \"NESC Revision Cycle\" dashboard landing page. It owns the\r\n * host-supplied configuration (`routePaths`, `apiBaseURL`, `userInfo`,\r\n * `userPermissions`), composes the four regions — welcome header, upcoming\r\n * meetings & events, your groups, and footer — and orchestrates data loading\r\n * and attendance actions through the {@link DashboardService}.\r\n *\r\n * The component is composition-first and host-agnostic: it subscribes to the\r\n * service observables (`upcomingEvents$`, `groups$`, the per-section states, the\r\n * attendance-state map, and the in-flight set) with `takeUntil(destroy$)` and\r\n * tracks `isMobileView` from the Presentation_Library\r\n * {@link BreakpointObserverService} (Req 13.1, 13.2, 13.5, 15.1, 15.2). Child\r\n * navigation `@Output()`s are composed into a single {@link dashboardNavigate}\r\n * stream of `{ path, id }` intents resolved from `routePaths` (falling back to\r\n * the default route configuration in `constants.json` when `routePaths` is\r\n * omitted) (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1, 11.5). Attendance `@Output()`s\r\n * are delegated to the service, and on failure the attendance-action error\r\n * message from `constants.json` is surfaced via the shared {@link AlertsService}\r\n * (Req 7.7, 7.8, 13.7). Per-row {@link AttendanceActionPermissions} are computed\r\n * from `userPermissions` and passed down to the rows (Req 12.3).\r\n * @export\r\n * @class DashboardComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-dashboard',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n UpcomingMeetingsEventsComponent,\r\n YourGroupsComponent,\r\n DashboardWelcomeHeaderComponent\r\n ],\r\n templateUrl: './dashboard.component.html',\r\n styleUrls: ['./dashboard.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n providers: [AlertsService],\r\n})\r\nexport class DashboardComponent implements OnInit, OnDestroy {\r\n /** User-facing strings and the default route config sourced from `constants.json`. */\r\n constants = constants;\r\n\r\n /** Host navigation paths; falls back to the `constants.json` default when omitted (Req 11.1, 11.5). */\r\n @Input() routePaths?: DashboardRouteConfig;\r\n\r\n /** The host application's API base URL, forwarded to the service (Req 11.2). */\r\n @Input() apiBaseURL!: string;\r\n\r\n /** The signed-in user's info used by the welcome header greeting (Req 11.3, 4.1). */\r\n @Input() userInfo!: DashboardUserInfo;\r\n\r\n /** The signed-in user's permissions used to gate attendance actions (Req 11.4, 12.3). */\r\n @Input() userPermissions!: UserPermission[];\r\n\r\n /** Emits a resolved navigation intent for the host to act on (Req 5.2, 6.4, 7.4, 8.2, 8.7, 11.1). */\r\n @Output() dashboardNavigate = new EventEmitter<DashboardNavigationIntent>();\r\n\r\n /** The user's upcoming events, bound to the upcoming section (Req 13.1, 13.2). */\r\n upcomingEvents: UpcomingEvent[] = [];\r\n\r\n /** The user's groups, bound to the groups section (Req 13.1, 13.2). */\r\n groups: GroupRow[] = [];\r\n\r\n /** The upcoming-events section's load/empty/error state (Req 13.1, 13.2, 13.5). */\r\n upcomingState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** The groups section's load/empty/error state (Req 13.1, 13.2, 13.5). */\r\n groupsState: DashboardSectionState = DashboardSectionState.LOADING;\r\n\r\n /** The per-meeting attendance-state map passed down to the rows. */\r\n attendanceStates: Record<string, AttendanceState> = {};\r\n\r\n /** The set of meeting ids with an attendance action awaiting resolution. */\r\n inFlightMeetingIds: ReadonlySet<string> = new Set<string>();\r\n\r\n /** The per-row attendance-action permissions derived from `userPermissions` (Req 12.3). */\r\n attendancePermissions: AttendanceActionPermissions = {\r\n canLogAttendance: false,\r\n canLeaveMeeting: false,\r\n };\r\n\r\n /** Whether the viewport is at/below the mobile breakpoint (Req 15.1, 15.2). */\r\n isMobileView = false;\r\n\r\n /** Whether the Upcoming Meetings & Events card is expanded. Starts expanded. */\r\n meetingsExpanded = true;\r\n\r\n /** Whether the Your Groups card is expanded. Starts collapsed. */\r\n groupsExpanded = false;\r\n\r\n /**\r\n * Section host elements used to scroll a \"Jump to\" target into view. Read as\r\n * ElementRef (not the component instance) so the native element is available\r\n * for scrollIntoView.\r\n */\r\n @ViewChild('upcomingSection', { read: ElementRef })\r\n upcomingSection?: ElementRef<HTMLElement>;\r\n @ViewChild('groupsSection', { read: ElementRef })\r\n groupsSection?: ElementRef<HTMLElement>;\r\n\r\n /**\r\n * Total number of meetings across the loaded upcoming events, shown in the\r\n * welcome header's \"Upcoming Meetings & Events\" shortcut badge.\r\n * @readonly\r\n * @memberof DashboardComponent\r\n */\r\n get meetingsCount(): number {\r\n return this.upcomingEvents.reduce(\r\n (total, event) => total + (event?.meetingCount ?? 0),\r\n 0\r\n );\r\n }\r\n\r\n /**\r\n * Number of loaded groups, shown in the welcome header's \"Your Groups\"\r\n * shortcut badge.\r\n * @readonly\r\n * @memberof DashboardComponent\r\n */\r\n get groupsCount(): number {\r\n return this.groups.length;\r\n }\r\n\r\n /** The current zero-based page index of the groups table. */\r\n groupsPageIndex = 0;\r\n\r\n /** The current page size of the groups table (5 rows per page per the design). */\r\n groupsPageSize = 5;\r\n\r\n /** Completes on destroy to tear down all subscriptions (Req 2.4, 2.5). */\r\n private readonly destroy$ = new Subject<boolean>();\r\n\r\n constructor(\r\n // eslint-disable-next-line no-unused-vars\r\n private dashboardService: DashboardService,\r\n // eslint-disable-next-line no-unused-vars\r\n private userPermissionsService: UserPermissionsService,\r\n // eslint-disable-next-line no-unused-vars\r\n private breakpointObserverService: BreakpointObserverService,\r\n // eslint-disable-next-line no-unused-vars\r\n private alertService: AlertsService // eslint-disable-next-line no-empty-function\r\n ) {}\r\n\r\n /**\r\n * Initializes the dashboard: forwards the host config to the service, derives\r\n * the per-row attendance permissions, kicks off the upcoming-events and groups\r\n * loads, and wires up subscriptions to the service state observables and the\r\n * breakpoint observer — all cleaned up via `takeUntil(destroy$)` (Req 11.2,\r\n * 11.4, 12.3, 13.1, 13.2, 13.5, 15.1, 15.2).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n ngOnInit(): void {\r\n this.dashboardService.setAppConfig(this.apiBaseURL, this.userPermissions);\r\n this.attendancePermissions =\r\n this.userPermissionsService.mapToAttendanceActionPermissions(\r\n this.userPermissions\r\n );\r\n\r\n this.subscribeToServiceState();\r\n this.subscribeToBreakpoint();\r\n this.loadUpcomingEvents();\r\n this.loadGroups();\r\n }\r\n\r\n /**\r\n * Tears down all subscriptions on destroy (Req 2.4, 2.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n ngOnDestroy(): void {\r\n this.destroy$.next(true);\r\n this.destroy$.complete();\r\n }\r\n\r\n /**\r\n * Handles the welcome-header \"Jump to\" date selection. The dashboard currently\r\n * has no date-scoped data load, so the selection is accepted without side\r\n * effects; the hook keeps the header's contract satisfied for future filtering.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onJumpToDateSelected(): void {\r\n // No date-scoped reload yet; retained for future date filtering (Req 4.4).\r\n }\r\n\r\n /**\r\n * Handles a welcome-header \"Jump to\" shortcut: opens the matching section's\r\n * card (so its content is visible) and smoothly scrolls it into view. It does\r\n * NOT navigate away — the shortcut is an in-page jump to the section.\r\n * @param {DashboardJumpTarget} target - The selected shortcut target.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onJumpToShortcut(target: DashboardJumpTarget): void {\r\n const section =\r\n target === DashboardJumpTarget.MEETINGS\r\n ? this.upcomingSection\r\n : this.groupsSection;\r\n\r\n if (target === DashboardJumpTarget.MEETINGS) {\r\n this.meetingsExpanded = true;\r\n } else {\r\n this.groupsExpanded = true;\r\n }\r\n\r\n // Scroll after the expand has rendered so the target's final position is used.\r\n setTimeout(() => {\r\n section?.nativeElement?.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'start',\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" upcoming-events navigation intent, targeting the\r\n * `viewAllEvents` route with no id (Req 5.2, 11.1).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewAllEvents(): void {\r\n this.emitNavigation(this.activeRouteConfig.viewAllEvents);\r\n }\r\n\r\n /**\r\n * Emits the \"View Event\" navigation intent, targeting the `eventDetail` route\r\n * with the event id (Req 6.4, 11.1).\r\n * @param {string} eventId - The id of the event to view.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewEvent(eventId: string): void {\r\n if (!eventId) {\r\n return;\r\n }\r\n this.dashboardNavigate.emit({\r\n path: this.activeRouteConfig.eventDetail,\r\n queryParams: { eventId },\r\n });\r\n }\r\n\r\n /**\r\n * Emits the open-meeting navigation intent to the view-meeting screen,\r\n * matching the reference list: a meeting under an event targets\r\n * `viewMeetingUnderEvent` with `eventId` + `meetingId` + `actionType=edit`; a\r\n * standalone meeting targets `viewMeeting` with `meetingId` + `actionType=edit`.\r\n * (Retained for the legacy string `openMeeting` output.)\r\n * @param {string} meetingId - The id of the meeting to open.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onOpenMeeting(meetingId: string): void {\r\n this.onNavigateToMeeting({ eventId: '', meetingId });\r\n }\r\n\r\n /**\r\n * Emits the \"View All\" groups navigation intent, targeting the\r\n * `viewAllGroups` route with no id (Req 8.2, 11.1).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onViewAllGroups(): void {\r\n this.emitNavigation(this.activeRouteConfig.viewAllGroups);\r\n }\r\n\r\n /**\r\n * Emits the group-detail navigation intent, targeting the `groupDetail` route\r\n * with the group id (Req 8.7, 11.1).\r\n * @param {string} groupId - The id of the selected group.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onGroupSelected(groupId: string): void {\r\n this.emitNavigation(this.activeRouteConfig.groupDetail, groupId);\r\n }\r\n\r\n /**\r\n * Updates the groups table paging state in response to a paginator change so\r\n * the groups section reflects the requested page (Req 8.10).\r\n * @param {PageChange} page - The requested page index and size.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onGroupsPageChange(page: PageChange): void {\r\n this.groupsPageIndex = page.pageIndex;\r\n this.groupsPageSize = page.pageSize;\r\n }\r\n\r\n /**\r\n * Lazily loads (or paginates) the child meetings of an expanded EVENT card via\r\n * the service, surfacing the attendance error message on failure. Each event\r\n * paginates independently. Loading feedback is handled by the host\r\n * application's global spinner, so no per-event loading state is tracked here.\r\n * @param {{ eventId: string; page: number; size: number }} request - The event id and one-based page to load.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLoadEventMeetings(request: {\r\n eventId: string;\r\n page: number;\r\n size: number;\r\n }): void {\r\n if (!request?.eventId) {\r\n return;\r\n }\r\n this.dashboardService\r\n .loadEventMeetings(request.eventId, request.page, request.size)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * Handles an attendance-button activation for an In-Progress meeting by\r\n * emitting a navigation intent to the view-meeting screen with `eventId`,\r\n * `meetingId`, and `actionType=edit` query params — producing a URL like\r\n * `/events-and-meetings/view-event/view-meeting?eventId=...&meetingId=...&actionType=edit`.\r\n * The Log Attendance popup is opened by that destination page.\r\n * @param {{ eventId: string; meetingId: string }} request - The meeting identity.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onNavigateToMeeting(request: {\r\n eventId: string;\r\n meetingId: string;\r\n logAttendance?: boolean;\r\n leaveMeeting?: boolean;\r\n }): void {\r\n if (!request?.meetingId) {\r\n return;\r\n }\r\n const config = this.activeRouteConfig;\r\n const queryParams: Record<string, string> = {\r\n meetingId: request.meetingId,\r\n actionType: 'edit',\r\n };\r\n // Meeting under an event → view-meeting-under-event with eventId; otherwise\r\n // the standalone view-meeting route.\r\n let path: string;\r\n if (request.eventId) {\r\n queryParams['eventId'] = request.eventId;\r\n path =\r\n config.viewMeetingUnderEvent ??\r\n this.constants.defaultRouteConfig.viewMeetingUnderEvent;\r\n } else {\r\n path =\r\n config.viewMeeting ?? this.constants.defaultRouteConfig.viewMeeting;\r\n }\r\n // Request the matching popup auto-open on the view-meeting page.\r\n if (request.logAttendance) {\r\n queryParams['logAttendance'] = 'true';\r\n } else if (request.leaveMeeting) {\r\n queryParams['leaveMeeting'] = 'true';\r\n }\r\n this.dashboardNavigate.emit({ path, queryParams });\r\n }\r\n\r\n /**\r\n * Delegates a log-attendance request to the service, surfacing the\r\n * attendance-action error message via the shared {@link AlertsService} on\r\n * failure while the service retains the prior displayed state (Req 7.7, 13.7).\r\n * @param {string} meetingId - The meeting to log attendance for.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLogAttendance(meetingId: string): void {\r\n this.dashboardService\r\n .logAttendance(meetingId)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * Delegates a leave-meeting request to the service, surfacing the\r\n * attendance-action error message via the shared {@link AlertsService} on\r\n * failure while the service retains the prior displayed state (Req 7.8, 13.7).\r\n * @param {string} meetingId - The meeting to leave.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n onLeaveMeeting(meetingId: string): void {\r\n this.dashboardService\r\n .leaveMeeting(meetingId)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => this.showAttendanceError(),\r\n });\r\n }\r\n\r\n /**\r\n * The route configuration in effect: the host-supplied `routePaths` when\r\n * provided, otherwise the default route config from `constants.json` so\r\n * navigation intents always carry valid targets (Req 11.1, 11.5).\r\n * @return {DashboardRouteConfig} The active route configuration.\r\n * @memberof DashboardComponent\r\n */\r\n private get activeRouteConfig(): DashboardRouteConfig {\r\n return this.routePaths ?? this.constants.defaultRouteConfig;\r\n }\r\n\r\n /**\r\n * Subscribes to the service's state observables, mirroring each into a local\r\n * field for the template to bind. All subscriptions are torn down via\r\n * `takeUntil(destroy$)` (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private subscribeToServiceState(): void {\r\n this.dashboardService.upcomingEvents$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((events) => (this.upcomingEvents = events));\r\n\r\n this.dashboardService.groups$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((groups) => {\r\n this.groups = groups;\r\n });\r\n\r\n this.dashboardService.upcomingState$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((state) => (this.upcomingState = state));\r\n\r\n this.dashboardService.groupsState$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((state) => (this.groupsState = state));\r\n\r\n this.dashboardService.attendanceStates$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((states) => (this.attendanceStates = states));\r\n\r\n this.dashboardService.inFlightMeetingIds$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((ids) => (this.inFlightMeetingIds = ids));\r\n }\r\n\r\n /**\r\n * Subscribes to the Presentation_Library breakpoint observer to keep\r\n * `isMobileView` in sync with the viewport (Req 15.1, 15.2).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private subscribeToBreakpoint(): void {\r\n this.breakpointObserverService\r\n .getBreakpoint()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((result: { matches: boolean }) => {\r\n this.isMobileView = result?.matches;\r\n });\r\n }\r\n\r\n /**\r\n * Triggers the upcoming-events load, setting the section to `ERROR` on failure\r\n * so only the section error region renders (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private loadUpcomingEvents(): void {\r\n this.dashboardService\r\n .loadUpcomingEvents()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => (this.upcomingState = DashboardSectionState.ERROR),\r\n });\r\n }\r\n\r\n /**\r\n * Triggers the groups load, setting the section to `ERROR` on failure so only\r\n * the section error region renders. Isolated from the upcoming-events load so\r\n * one failing does not affect the other (Req 13.1, 13.2, 13.5).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private loadGroups(): void {\r\n this.dashboardService\r\n .loadGroups()\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: () => (this.groupsState = DashboardSectionState.ERROR),\r\n });\r\n }\r\n\r\n /**\r\n * Composes and emits a {@link DashboardNavigationIntent} for the host from the\r\n * resolved target path and an optional triggering id (Req 11.1).\r\n * @param {string} path - The resolved target route path.\r\n * @param {string} [id] - The triggering identifier, when applicable.\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private emitNavigation(path: string, id?: string): void {\r\n this.dashboardNavigate.emit(id ? { path, id } : { path });\r\n }\r\n\r\n /**\r\n * Surfaces the attendance-action error message from `constants.json` via the\r\n * shared {@link AlertsService} (Req 13.7).\r\n * @return {void}\r\n * @memberof DashboardComponent\r\n */\r\n private showAttendanceError(): void {\r\n this.alertService?.showMessage({\r\n status: 'custom',\r\n message:\r\n this.constants?.attendance?.errorMessage ??\r\n 'Unable to update your attendance. Please try again.',\r\n alertType: AlertType.ERROR,\r\n isCloseNeeded: true,\r\n });\r\n }\r\n}\r\n","<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 (navigateToMeeting)=\"onNavigateToMeeting($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","import { CommonModule } from '@angular/common';\r\nimport { Component, Input, ViewEncapsulation } from '@angular/core';\r\nimport { Legend, LegendComponent } from '@ieeesa-npm/presentation';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * Member_Level_Badge renders a single member-level value as a colored pill.\r\n * It reuses the Presentation_Library Legend component for the pill primitive,\r\n * sourcing the level-to-color mapping from `constants.json` (`memberLevel.colorMap`)\r\n * with a nullish-coalescing fallback to the configured default color.\r\n * @export\r\n * @class MemberLevelBadgeComponent\r\n */\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ieeesa-member-level-badge',\r\n standalone: true,\r\n imports: [CommonModule, LegendComponent],\r\n templateUrl: './member-level-badge.component.html',\r\n styleUrls: ['./member-level-badge.component.scss'],\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class MemberLevelBadgeComponent {\r\n constants = constants;\r\n\r\n private memberLevelValue = '';\r\n\r\n @Input()\r\n set memberLevel(value: string) {\r\n this.memberLevelValue = value ?? '';\r\n this.legends = this.buildLegends(this.memberLevelValue);\r\n }\r\n get memberLevel(): string {\r\n return this.memberLevelValue;\r\n }\r\n\r\n /** The Legend input consumed by the Presentation_Library Legend component. */\r\n legends: Legend[] = this.buildLegends('');\r\n\r\n /**\r\n * Builds the single-item Legend list for the supplied member level, resolving\r\n * the pill color from the `constants.json` color map and falling back to the\r\n * configured default color when the level has no explicit mapping.\r\n * @param {string} memberLevel - The member-level label to render.\r\n * @return {Legend[]} A single-element Legend array for the Legend component.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private buildLegends(memberLevel: string): Legend[] {\r\n return [\r\n {\r\n label: memberLevel,\r\n color: this.resolveColorClass(memberLevel),\r\n hierarchy: 0,\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Resolves the CSS modifier class for a member level from the `constants.json`\r\n * color map, using the `??` fallback to the `default` entry when the level is\r\n * missing from the map.\r\n * @param {string} memberLevel - The member-level label to resolve a color for.\r\n * @return {string} The CSS modifier class applied to the pill.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private resolveColorClass(memberLevel: string): string {\r\n const colorMap = this.constants?.memberLevel?.colorMap as\r\n | Record<string, string>\r\n | undefined;\r\n const token =\r\n colorMap?.[memberLevel] ?? colorMap?.['default'] ?? '$ieeesa-color-neutral';\r\n return this.toColorClass(token);\r\n }\r\n\r\n /**\r\n * Converts a shared-styles color token (for example `$ieeesa-color-success`)\r\n * into a valid BEM-style CSS modifier class defined in this component's SCSS.\r\n * @param {string} token - The color token from the color map.\r\n * @return {string} A valid CSS class name.\r\n * @memberof MemberLevelBadgeComponent\r\n */\r\n private toColorClass(token: string): string {\r\n const normalized = token.replace(/^\\$ieeesa-color-/, '').replace(/^\\$/, '');\r\n return `ieeesa-member-level-badge--${normalized || 'neutral'}`;\r\n }\r\n}\r\n","<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","import { NgModule } from '@angular/core';\r\nimport { DashboardComponent } from './dashboard.component';\r\n\r\n@NgModule({\r\n imports: [DashboardComponent],\r\n exports: [DashboardComponent],\r\n})\r\nexport class DashboardModule {}\r\n","import { Routes } from '@angular/router';\r\n\r\nexport const DASHBOARD_ROUTES: Routes = [\r\n {\r\n path: '',\r\n loadComponent: () =>\r\n import('./dashboard.component').then((m) => m.DashboardComponent),\r\n },\r\n];\r\n","/**\r\n * Request payloads for the dashboard \"home\" events-&-meetings backend calls.\r\n *\r\n * `appId` is taken from the JWT, so it is never sent. `page` / `size` are\r\n * required; `sortColumn` / `ascendingOrder` / `searchTerm` are optional on the\r\n * list endpoint (the service always orders by start date asc, then name asc;\r\n * `searchTerm`, when present, must be at least 3 characters).\r\n */\r\n\r\n/** Payload for `POST {apiBaseUrl}/meetings/home/eventsAndMeetings` (the section list). */\r\nexport interface EventMeetingListPayload {\r\n payload: {\r\n page: number;\r\n size: number;\r\n sortColumn?: string;\r\n ascendingOrder?: boolean;\r\n searchTerm?: string | null;\r\n };\r\n}\r\n\r\n/**\r\n * Payload for `POST {apiBaseUrl}/meetings/home/events/{eventId}/meetings`\r\n * (per-event drill-down). The `eventId` is in the URL path, not the body; only\r\n * `page` / `size` are used.\r\n */\r\nexport interface EventMeetingDetailPayload {\r\n payload: {\r\n page: number;\r\n size: number;\r\n };\r\n}\r\n","import { DashboardRouteConfig } from '../models/dashboard-route-config.model';\r\n\r\nexport const DashboardRoutePathsMock: DashboardRouteConfig = {\r\n eventDetail: 'events-and-meetings/view-event',\r\n meetingDetail: 'events-and-meetings/view-meeting',\r\n /*\r\n * The demo app only registers a flat `groups` route (no group-detail screen),\r\n * so group-row navigation targets it rather than a `view-group` child that the\r\n * demo does not implement. A consuming app with a real group-detail route\r\n * supplies its own path via the `routePaths` input.\r\n */\r\n groupDetail: 'groups',\r\n viewAllEvents: 'events-and-meetings/view-events-meetings-list',\r\n viewAllGroups: 'groups',\r\n};\r\n","import { UserPermission } from '@ieeesa-npm/models';\r\n\r\nexport const DashboardUserPermissionsMock: UserPermission[] = [\r\n {\r\n permissionName: 'View Events',\r\n permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',\r\n },\r\n {\r\n permissionName: 'View Meetings',\r\n permissionId: 'PERM_5dd65526-5df3-428d-8acc-cee7ffb5f261',\r\n },\r\n {\r\n permissionName: 'View Groups',\r\n permissionId: 'PERM_9a1f0c84-2b77-4e2a-9f3d-1c6b4e9a8d20',\r\n },\r\n {\r\n permissionName: 'Log Attendance',\r\n permissionId: 'PERM_1b2c3d4e-5f60-4718-8293-aabbccddeeff',\r\n },\r\n {\r\n permissionName: 'Leave Meeting',\r\n permissionId: 'PERM_6f5e4d3c-2b1a-4908-8716-ffeeddccbbaa',\r\n },\r\n];\r\n","import { AttendanceState } from '../models/attendance-state.model';\r\nimport { GroupRow } from '../models/group-row.model';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\nimport {\r\n UpcomingEvent,\r\n UpcomingItemKind,\r\n} from '../models/upcoming-event.model';\r\n\r\n/**\r\n * Mock upcoming-events + groups fixtures for the dashboard library.\r\n *\r\n * These exercise the key presentation edge cases:\r\n * - empty/undefined `groupOrCommittee` and `roomOrLocation` (empty-field placeholder)\r\n * - a mix of `CURRENTLY_ATTENDING` / `NOT_ATTENDING` attendance states\r\n * - events with many meetings so per-card pagination is exercised\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardUpcomingEventsMock: UpcomingEvent[] = [\r\n {\r\n eventId: 'EVT-001',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'NESC Revision Cycle Kickoff',\r\n status: 'In Progress',\r\n dayIndicator: 'Day 1 of 3',\r\n meetingCount: 6,\r\n openForAttendanceCount: 3,\r\n startDate: '2025-03-14T09:00:00',\r\n endDate: '2025-03-16T17:00:00',\r\n timezone: 'America/New_York',\r\n meetings: [\r\n {\r\n meetingId: 'MTG-001',\r\n meetingName: 'Opening Plenary',\r\n groupOrCommittee: 'NESC Main Committee',\r\n roomOrLocation: 'Grand Ballroom A',\r\n meetingDate: '2025-03-14T09:00:00',\r\n meetingTime: '2025-03-14T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-002',\r\n meetingName: 'Subcommittee 1 Working Session',\r\n groupOrCommittee: 'Subcommittee 1 - Grounding',\r\n // RoomOrLocation intentionally omitted to exercise the empty-field placeholder.\r\n meetingDate: '2025-03-14T11:00:00',\r\n meetingTime: '2025-03-14T11:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-003',\r\n meetingName: 'Subcommittee 2 Working Session',\r\n // GroupOrCommittee intentionally empty to exercise the empty-field placeholder.\r\n groupOrCommittee: '',\r\n roomOrLocation: 'Room 204',\r\n meetingDate: '2025-03-14T13:30:00',\r\n meetingTime: '2025-03-14T13:30:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-004',\r\n meetingName: 'Editorial Review',\r\n groupOrCommittee: 'Editorial Task Force',\r\n roomOrLocation: 'Room 118',\r\n meetingDate: '2025-03-15T09:00:00',\r\n meetingTime: '2025-03-15T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-005',\r\n meetingName: 'Interpretations Panel',\r\n groupOrCommittee: 'Interpretations Subcommittee',\r\n roomOrLocation: 'Room 310',\r\n meetingDate: '2025-03-15T14:00:00',\r\n meetingTime: '2025-03-15T14:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-006',\r\n meetingName: 'Closing Plenary',\r\n groupOrCommittee: 'NESC Main Committee',\r\n roomOrLocation: 'Grand Ballroom A',\r\n meetingDate: '2025-03-16T15:00:00',\r\n meetingTime: '2025-03-16T15:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n ],\r\n },\r\n {\r\n eventId: 'EVT-002',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'Standards Board Quarterly Meeting',\r\n status: 'Upcoming',\r\n dayIndicator: 'Day 1 of 1',\r\n meetingCount: 3,\r\n openForAttendanceCount: 1,\r\n startDate: '2025-04-02T08:30:00',\r\n endDate: '2025-04-02T16:00:00',\r\n timezone: 'America/Los_Angeles',\r\n meetings: [\r\n {\r\n meetingId: 'MTG-101',\r\n meetingName: 'Board Opening Remarks',\r\n groupOrCommittee: 'Standards Board',\r\n roomOrLocation: 'Pacific Hall',\r\n meetingDate: '2025-04-02T08:30:00',\r\n meetingTime: '2025-04-02T08:30:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: true,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-102',\r\n meetingName: 'Ballot Review Session',\r\n // Both optional location/group fields omitted to exercise placeholders.\r\n meetingDate: '2025-04-02T10:30:00',\r\n meetingTime: '2025-04-02T10:30:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n },\r\n {\r\n meetingId: 'MTG-103',\r\n meetingName: 'Action Items & Wrap-up',\r\n groupOrCommittee: 'Standards Board',\r\n roomOrLocation: 'Pacific Hall',\r\n meetingDate: '2025-04-02T15:00:00',\r\n meetingTime: '2025-04-02T15:00:00',\r\n timezone: 'America/Los_Angeles',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.CURRENTLY_ATTENDING,\r\n },\r\n ],\r\n },\r\n {\r\n eventId: 'EVT-003',\r\n kind: UpcomingItemKind.EVENT,\r\n title: 'Working Group Interim',\r\n status: 'Upcoming',\r\n // DayIndicator intentionally omitted (optional field).\r\n meetingCount: 0,\r\n openForAttendanceCount: 0,\r\n startDate: '2025-05-20T09:00:00',\r\n endDate: '2025-05-20T12:00:00',\r\n timezone: 'Europe/London',\r\n meetings: [],\r\n },\r\n];\r\n\r\n/**\r\n * Mock a single meeting row with an empty `meetingId` to exercise the\r\n * non-actionable (empty/undefined id) path in the meeting row component.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardNonActionableMeetingMock: MeetingRow = {\r\n meetingId: '',\r\n meetingName: 'Unscheduled Placeholder Session',\r\n groupOrCommittee: '',\r\n meetingDate: '2025-06-01T09:00:00',\r\n meetingTime: '2025-06-01T09:00:00',\r\n timezone: 'America/New_York',\r\n isOpenForAttendance: false,\r\n attendanceState: AttendanceState.NOT_ATTENDING,\r\n};\r\n\r\n/**\r\n * Mock groups fixtures for the dashboard \"Your Groups\" section.\r\n *\r\n * Includes rows with missing optional fields (`type`, `officerRole`,\r\n * `affiliation`) and a spread of member levels so the member-level badge\r\n * colour map and empty-field placeholders are exercised.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n */\r\nexport const DashboardGroupsMock: GroupRow[] = [\r\n {\r\n groupId: 'GRP-001',\r\n group: 'NESC Main Committee',\r\n type: 'Committee',\r\n officerRole: 'Chair',\r\n affiliation: 'Employer Corp',\r\n memberLevel: 'Senior Member',\r\n },\r\n {\r\n groupId: 'GRP-002',\r\n group: 'Subcommittee 1 - Grounding',\r\n type: 'Subcommittee',\r\n // OfficerRole intentionally omitted (member with no officer role).\r\n affiliation: 'Standards Member',\r\n memberLevel: 'Member',\r\n },\r\n {\r\n groupId: 'GRP-003',\r\n group: 'Editorial Task Force',\r\n // Type and affiliation intentionally omitted to exercise placeholders.\r\n officerRole: 'Secretary',\r\n memberLevel: 'Fellow',\r\n },\r\n {\r\n groupId: 'GRP-004',\r\n group: 'Interpretations Subcommittee',\r\n type: 'Subcommittee',\r\n officerRole: 'Member',\r\n affiliation: 'Tech Solutions Inc',\r\n memberLevel: 'Associate Member',\r\n },\r\n {\r\n groupId: 'GRP-005',\r\n group: 'Standards Board',\r\n type: 'Board',\r\n officerRole: 'Vice Chair',\r\n affiliation: 'CodeCraft Studio',\r\n memberLevel: 'Senior Member',\r\n },\r\n];\r\n","/*\r\n * Public API Surface of dashboard\r\n */\r\n\r\n// Container component + navigation intent type (DashboardComponent, DashboardNavigationIntent)\r\nexport * from './lib/dashboard.component';\r\n\r\n// Child components\r\nexport * from './lib/components/welcome-header/dashboard-welcome-header.component';\r\nexport * from './lib/components/upcoming-meetings-events/upcoming-meetings-events.component';\r\nexport * from './lib/components/event-group-card/event-group-card.component';\r\nexport * from './lib/components/meeting-attendance-row/meeting-attendance-row.component';\r\nexport * from './lib/components/your-groups/your-groups.component';\r\nexport * from './lib/components/member-level-badge/member-level-badge.component';\r\n\r\n// Module + routes\r\nexport * from './lib/dashboard.module';\r\nexport * from './lib/dashboard.routes';\r\n\r\n// Models\r\nexport * from './lib/models/dashboard-route-config.model';\r\nexport * from './lib/models/attendance-state.model';\r\nexport * from './lib/models/dashboard-section-state.model';\r\nexport * from './lib/models/page-change.model';\r\nexport * from './lib/models/dashboard-user-info.model';\r\nexport * from './lib/models/meeting-row.model';\r\nexport * from './lib/models/upcoming-event.model';\r\nexport * from './lib/models/event-meeting-list-item.model';\r\nexport * from './lib/models/event-meeting-list-payload.model';\r\nexport * from './lib/models/group-row.model';\r\nexport * from './lib/models/attendance-action-permissions.model';\r\nexport * from './lib/models/dashboard-list-response.model';\r\n\r\n// Services\r\nexport * from './lib/services/dashboard.service';\r\nexport * from './lib/services/user-permissions.service';\r\n\r\n// Asset mocks consumed by the demo app\r\nexport * from './lib/assets/dashboard-route-paths.mock';\r\nexport * from './lib/assets/dashboard-user-permissions.mock';\r\nexport * from './lib/assets/dashboard-mock';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["screenTexts","constants","i1","i1.DashboardService","i2.UserPermissionsService","i4","i5"],"mappings":"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"}
|