@ieeesa-npm/dashboard 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +75 -3
  2. package/esm2022/ieeesa-npm-dashboard.mjs +5 -0
  3. package/esm2022/lib/assets/constants.json +141 -0
  4. package/esm2022/lib/assets/dashboard-mock.mjs +217 -0
  5. package/esm2022/lib/assets/dashboard-route-paths.mock.mjs +12 -0
  6. package/esm2022/lib/assets/dashboard-user-permissions.mock.mjs +23 -0
  7. package/esm2022/lib/assets/date-formats.mjs +28 -0
  8. package/esm2022/lib/components/event-group-card/event-group-card.component.mjs +277 -0
  9. package/esm2022/lib/components/meeting-attendance-row/meeting-attendance-row.component.mjs +181 -0
  10. package/esm2022/lib/components/member-level-badge/member-level-badge.component.mjs +79 -0
  11. package/esm2022/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.mjs +163 -0
  12. package/esm2022/lib/components/welcome-header/dashboard-welcome-header.component.mjs +151 -0
  13. package/esm2022/lib/components/your-groups/your-groups.component.mjs +206 -0
  14. package/esm2022/lib/dashboard.component.mjs +377 -0
  15. package/esm2022/lib/dashboard.module.mjs +16 -0
  16. package/esm2022/lib/dashboard.routes.mjs +7 -0
  17. package/esm2022/lib/models/attendance-action-permissions.model.mjs +2 -0
  18. package/esm2022/lib/models/attendance-state.model.mjs +7 -0
  19. package/esm2022/lib/models/dashboard-list-response.model.mjs +2 -0
  20. package/esm2022/lib/models/dashboard-route-config.model.mjs +2 -0
  21. package/esm2022/lib/models/dashboard-section-state.model.mjs +9 -0
  22. package/esm2022/lib/models/dashboard-user-info.model.mjs +2 -0
  23. package/esm2022/lib/models/group-row.model.mjs +2 -0
  24. package/esm2022/lib/models/meeting-row.model.mjs +2 -0
  25. package/esm2022/lib/models/page-change.model.mjs +2 -0
  26. package/esm2022/lib/models/upcoming-event.model.mjs +2 -0
  27. package/esm2022/lib/services/attendance-reducers.mjs +54 -0
  28. package/esm2022/lib/services/dashboard.service.mjs +208 -0
  29. package/esm2022/lib/services/user-permissions.service.mjs +50 -0
  30. package/esm2022/lib/utils/attendance-action.util.mjs +53 -0
  31. package/esm2022/public-api.mjs +34 -0
  32. package/fesm2022/ieeesa-npm-dashboard.mjs +2234 -0
  33. package/fesm2022/ieeesa-npm-dashboard.mjs.map +1 -0
  34. package/index.d.ts +5 -0
  35. package/lib/assets/dashboard-mock.d.ts +31 -0
  36. package/lib/assets/dashboard-route-paths.mock.d.ts +2 -0
  37. package/lib/assets/dashboard-user-permissions.mock.d.ts +2 -0
  38. package/lib/assets/date-formats.d.ts +27 -0
  39. package/lib/components/event-group-card/event-group-card.component.d.ts +300 -0
  40. package/lib/components/meeting-attendance-row/meeting-attendance-row.component.d.ts +239 -0
  41. package/lib/components/member-level-badge/member-level-badge.component.d.ts +161 -0
  42. package/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.d.ts +238 -0
  43. package/lib/components/welcome-header/dashboard-welcome-header.component.d.ts +98 -0
  44. package/lib/components/your-groups/your-groups.component.d.ts +110 -0
  45. package/lib/dashboard.component.d.ts +376 -0
  46. package/lib/dashboard.module.d.ts +7 -0
  47. package/lib/dashboard.routes.d.ts +2 -0
  48. package/lib/models/attendance-action-permissions.model.d.ts +4 -0
  49. package/lib/models/attendance-state.model.d.ts +4 -0
  50. package/lib/models/dashboard-list-response.model.d.ts +5 -0
  51. package/lib/models/dashboard-route-config.model.d.ts +7 -0
  52. package/lib/models/dashboard-section-state.model.d.ts +6 -0
  53. package/lib/models/dashboard-user-info.model.d.ts +5 -0
  54. package/lib/models/group-row.model.d.ts +8 -0
  55. package/lib/models/meeting-row.model.d.ts +12 -0
  56. package/lib/models/page-change.model.d.ts +4 -0
  57. package/lib/models/upcoming-event.model.d.ts +13 -0
  58. package/lib/services/attendance-reducers.d.ts +43 -0
  59. package/lib/services/dashboard.service.d.ts +119 -0
  60. package/lib/services/user-permissions.service.d.ts +31 -0
  61. package/lib/utils/attendance-action.util.d.ts +38 -0
  62. package/package.json +30 -3
  63. package/public-api.d.ts +24 -0
@@ -0,0 +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/assets/date-formats.ts","../../../projects/dashboard/src/lib/utils/attendance-action.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/assets/dashboard-mock.ts","../../../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/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/assets/dashboard-route-paths.mock.ts","../../../projects/dashboard/src/lib/assets/dashboard-user-permissions.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","/**\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","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 { DateTime } from 'luxon';\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 * as constants 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 constants = constants;\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 /** 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 return this.formatIso(this.meeting?.meetingDate, DateFormats.displayFormat);\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 time = this.formatIso(\r\n this.meeting?.meetingTime,\r\n DateFormats.timeMeridiemFormat\r\n );\r\n const timezone = this.meeting?.timezone ?? '';\r\n return timezone ? `${time} ${timezone}` : time;\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 /**\r\n * Parses an ISO string with luxon and formats it with the supplied token,\r\n * returning the raw value unchanged when it is missing or unparseable.\r\n * @param {string | undefined} isoValue - The ISO date/time string.\r\n * @param {string} format - The luxon format token.\r\n * @return {string} The formatted value or the raw/empty fallback.\r\n * @memberof MeetingAttendanceRowComponent\r\n */\r\n private formatIso(isoValue: string | undefined, format: string): string {\r\n if (!isoValue) {\r\n return '';\r\n }\r\n const parsed = DateTime.fromISO(isoValue, { setZone: true });\r\n return parsed.isValid ? parsed.toFormat(format) : isoValue;\r\n }\r\n}\r\n","<div class=\"ieeesa-meeting-attendance-row\">\r\n <div class=\"ieeesa-meeting-attendance-row__details\">\r\n <!-- Meeting-name link (emits openMeeting; non-actionable when id missing). -->\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 ?? 'View meeting details'\"\r\n (click)=\"onOpenMeeting()\"\r\n >\r\n {{ meeting?.meetingName }}\r\n </button>\r\n\r\n <dl class=\"ieeesa-meeting-attendance-row__meta\">\r\n <div class=\"ieeesa-meeting-attendance-row__meta-item\">\r\n <dt class=\"ieeesa-meeting-attendance-row__meta-term\">\r\n {{ constants?.groupsSection?.columns?.group ?? 'Group' }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__meta-value\">\r\n {{ resolveFieldValue(meeting?.groupOrCommittee) }}\r\n </dd>\r\n </div>\r\n\r\n <div class=\"ieeesa-meeting-attendance-row__meta-item\">\r\n <dt class=\"ieeesa-meeting-attendance-row__meta-term\">\r\n {{ constants?.groupsSection?.columns?.affiliation ?? 'Location' }}\r\n </dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__meta-value\">\r\n {{ resolveFieldValue(meeting?.roomOrLocation) }}\r\n </dd>\r\n </div>\r\n\r\n <div class=\"ieeesa-meeting-attendance-row__meta-item\">\r\n <dt class=\"ieeesa-meeting-attendance-row__meta-term\">Date</dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__meta-value\">\r\n {{ formattedDate }}\r\n </dd>\r\n </div>\r\n\r\n <div class=\"ieeesa-meeting-attendance-row__meta-item\">\r\n <dt class=\"ieeesa-meeting-attendance-row__meta-term\">Time</dt>\r\n <dd class=\"ieeesa-meeting-attendance-row__meta-value\">\r\n {{ formattedTime }}\r\n </dd>\r\n </div>\r\n </dl>\r\n </div>\r\n\r\n <div class=\"ieeesa-meeting-attendance-row__actions\">\r\n <!-- Currently-attending indicator shown only in the attending state. -->\r\n <span\r\n *ngIf=\"isCurrentlyAttending\"\r\n class=\"ieeesa-meeting-attendance-row__attending-indicator\"\r\n >\r\n {{ constants?.meetingRow?.currentlyAttendingIndicator ?? 'Currently Attending' }}\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 ?? 'Log attendance for this meeting'\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants?.meetingRow?.logAttendanceLabel ?? 'Log Attendance' }}\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 ?? 'Leave this meeting'\"\r\n (click)=\"onAttendanceAction()\"\r\n >\r\n {{ constants?.meetingRow?.leaveMeetingLabel ?? 'Leave Meeting' }}\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 { DateTime } from 'luxon';\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 { UpcomingEvent } 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 * as constants 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 constants = constants;\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 /** 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 * 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 /** The total number of meetings for the event (paginator length). */\r\n get totalMeetings(): number {\r\n return this.meetings.length;\r\n }\r\n\r\n /**\r\n * The slice of meetings for the current page, used by the row `*ngFor`.\r\n * @return {MeetingRow[]} The meetings on the current page.\r\n * @memberof EventGroupCardComponent\r\n */\r\n get pagedMeetings(): MeetingRow[] {\r\n const start = this.pageIndex * this.pageSize;\r\n return this.meetings.slice(start, start + this.pageSize);\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 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 const prefix = toggle?.showLabelPrefix ?? 'Show Meetings (';\r\n const suffix = toggle?.showLabelSuffix ?? ' open for attendance)';\r\n return `${prefix}${this.event?.openForAttendanceCount ?? 0}${suffix}`;\r\n }\r\n\r\n /** The luxon-formatted start date of the event (Req 6.2). */\r\n get formattedStartDate(): string {\r\n return this.formatIso(this.event?.startDate, DateFormats.displayFormat);\r\n }\r\n\r\n /** The luxon-formatted end date of the event (Req 6.2). */\r\n get formattedEndDate(): string {\r\n return this.formatIso(this.event?.endDate, DateFormats.displayFormat);\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 (Req 6.6).\r\n * @memberof EventGroupCardComponent\r\n */\r\n onToggleMeetingList(): void {\r\n this.isMeetingListOpen = !this.isMeetingListOpen;\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 }\r\n\r\n /**\r\n * Parses an ISO string with luxon and formats it with the supplied token,\r\n * returning the raw value unchanged when it is missing or unparseable.\r\n * @param {string | undefined} isoValue - The ISO date/time string.\r\n * @param {string} format - The luxon format token.\r\n * @return {string} The formatted value or the raw/empty fallback.\r\n * @memberof EventGroupCardComponent\r\n */\r\n private formatIso(isoValue: string | undefined, format: string): string {\r\n if (!isoValue) {\r\n return '';\r\n }\r\n const parsed = DateTime.fromISO(isoValue, { setZone: true });\r\n return parsed.isValid ? parsed.toFormat(format) : isoValue;\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>\r\n <header class=\"ieeesa-event-group-card__header\">\r\n <div class=\"ieeesa-event-group-card__heading\">\r\n <!-- Status badge (Req 6.1). -->\r\n <span\r\n *ngIf=\"event?.status\"\r\n class=\"ieeesa-event-group-card__status\"\r\n >\r\n {{ event?.status }}\r\n </span>\r\n\r\n <!-- Event title (Req 6.1). -->\r\n <h3 class=\"ieeesa-event-group-card__title\">{{ event?.title }}</h3>\r\n\r\n <!-- Day indicator (Req 6.1). -->\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 <!-- View Event action (Req 6.3, 6.4). -->\r\n <button\r\n type=\"button\"\r\n class=\"ieeesa-event-group-card__view-event\"\r\n [attr.aria-label]=\"constants?.eventGroupCard?.ariaLabel?.viewEvent ?? 'View event details'\"\r\n (click)=\"onViewEvent()\"\r\n >\r\n {{ constants?.eventGroupCard?.viewEventLabel ?? 'View Event' }}\r\n </button>\r\n </header>\r\n\r\n <dl class=\"ieeesa-event-group-card__meta\">\r\n <!-- Meeting-count summary sub-line (Req 6.1). -->\r\n <div class=\"ieeesa-event-group-card__meta-item\">\r\n <dd class=\"ieeesa-event-group-card__meeting-count\">\r\n {{ meetingCountSummary }}\r\n </dd>\r\n </div>\r\n\r\n <!-- Start / end date (Req 6.2). -->\r\n <div class=\"ieeesa-event-group-card__meta-item\">\r\n <dd class=\"ieeesa-event-group-card__dates\">\r\n {{ formattedStartDate }}<ng-container *ngIf=\"formattedEndDate\">\r\n &ndash; {{ formattedEndDate }}</ng-container>\r\n </dd>\r\n </div>\r\n\r\n <!-- Timezone (Req 6.2). -->\r\n <div class=\"ieeesa-event-group-card__meta-item\" *ngIf=\"event?.timezone\">\r\n <dd class=\"ieeesa-event-group-card__timezone\">{{ event?.timezone }}</dd>\r\n </div>\r\n </dl>\r\n\r\n <!-- Meeting-list show/hide toggle labeled with open-for-attendance count (Req 6.5, 6.6). -->\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 ?? 'Show or hide the meeting list for this event'\"\r\n (click)=\"onToggleMeetingList()\"\r\n >\r\n {{ meetingListToggleLabel }}\r\n </button>\r\n\r\n <!-- Meeting list + per-card paginator, shown only when the toggle is open (Req 6.7, 6.8). -->\r\n <div *ngIf=\"isMeetingListOpen\" class=\"ieeesa-event-group-card__meetings\">\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 ?? 'Meeting list pagination'\"\r\n >\r\n <!-- Range + total count label from constants.json (Req 6.8). -->\r\n <span class=\"ieeesa-event-group-card__paginator-range\">\r\n {{ rangeLabel }}\r\n </span>\r\n\r\n <!-- Presentation paginator emitting pageChange({ pageIndex, pageSize }) (Req 6.9, 3.3). -->\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</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 { 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 constants 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: [CommonModule, LoaderComponent, EventGroupCardComponent],\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 constants = constants;\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 /** Whether the section's card list is currently expanded; starts collapsed. */\r\n isExpanded = false;\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 }\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","<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 ?? 'Upcoming Meetings & Events' }}\r\n </h2>\r\n </div>\r\n\r\n <!-- View All link + Expand/Collapse toggle, matching the Your Groups card\r\n header (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 ?? 'View all upcoming meetings and events'\"\r\n (click)=\"onViewAll()\"\r\n >\r\n {{ constants?.upcomingSection?.viewAllLabel ?? 'View All' }}\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 ?? 'Collapse or expand upcoming meetings and events'\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <span>{{ isExpanded ? (constants?.upcomingSection?.collapseLabel ?? 'Collapse') : (constants?.upcomingSection?.expandLabel ?? 'Expand') }}</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\r\n *ngIf=\"isExpanded\"\r\n class=\"ieeesa-upcoming-meetings-events__body\"\r\n >\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 events; 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 ></ieeesa-event-group-card>\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 ?? 'You have no upcoming meetings or events.' }}\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 ?? 'Unable to load upcoming meetings and events. Please try again.' }}\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 { AttendanceState } from '../models/attendance-state.model';\r\nimport { GroupRow } from '../models/group-row.model';\r\nimport { MeetingRow } from '../models/meeting-row.model';\r\nimport { UpcomingEvent } 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 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 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 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","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 { PageEvent } from '@angular/material/paginator';\r\nimport {\r\n DataTableComponent,\r\n LoaderComponent,\r\n PaginatorConfig,\r\n TableActions,\r\n TableColumnSchema,\r\n TableColumnType,\r\n} from '@ieeesa-npm/presentation';\r\nimport { DashboardSectionState } from '../../models/dashboard-section-state.model';\r\nimport { GroupRow } from '../../models/group-row.model';\r\nimport { PageChange } from '../../models/page-change.model';\r\nimport { DashboardGroupsMock } from '../../assets/dashboard-mock';\r\nimport * as constants from '../../assets/constants.json';\r\n\r\n/**\r\n * Groups_Section (`ieeesa-your-groups`) renders the signed-in user's groups as a\r\n * paginated table inside a collapsible card. It shows the section title and a\r\n * \"{n} Groups\" count, a \"View All\" link, and a collapse/expand toggle that\r\n * controls the table's visibility (reflected via `[attr.aria-expanded]`). When\r\n * loaded it renders the groups table with the Presentation_Library\r\n * {@link DataTableComponent} using the columns Group, Type, Officer Role,\r\n * Affiliation, and Member Level (labels sourced from `constants.json`). The\r\n * Group cell is a LINK column that emits `groupSelected(groupId)`, and the\r\n * Member Level cell renders as a colored pill via the data-table's inline-badge\r\n * mechanism (green for voting-type levels, amber otherwise).\r\n *\r\n * The section is purely presentational: it emits navigation and pagination\r\n * intents via `@Output()` and never performs navigation or HTTP itself. The\r\n * Loader / empty-state / error regions are mutually exclusive and driven solely\r\n * by the `sectionState` input.\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: [CommonModule, DataTableComponent, LoaderComponent],\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 /**\r\n * The groups rendered in the table. Defaults to the dummy fixture so the\r\n * table shows immediately while the API integration is pending; the host can\r\n * override it once real data is wired in.\r\n */\r\n @Input() groups: GroupRow[] = DashboardGroupsMock;\r\n\r\n /**\r\n * The section's load/empty/error state driving the mutually-exclusive\r\n * regions. Defaults to LOADED (no loader) since the component renders dummy\r\n * data for now; the host can set LOADING/EMPTY/ERROR once the API is wired.\r\n */\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 /** Current zero-based page index. */\r\n @Input() pageIndex = 0;\r\n\r\n /** Current page size. */\r\n @Input() pageSize = 10;\r\n\r\n /** Emits the selected group's id when its name link is clicked. */\r\n @Output() groupSelected = new EventEmitter<string>();\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 /** Whether the card is expanded (table visible). Starts collapsed. */\r\n isExpanded = false;\r\n\r\n /** Data-table action flags: pagination only (no search/filter/add/edit). */\r\n readonly tableActions: TableActions = {\r\n isPaginationNeeded: true,\r\n };\r\n\r\n /**\r\n * The count shown in the header subtitle, preferring the server total and\r\n * falling back to the current page length.\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 * The paginator config derived from the total/pageSize inputs.\r\n * @readonly\r\n * @memberof YourGroupsComponent\r\n */\r\n get paginatorConfig(): PaginatorConfig {\r\n return {\r\n recordsPerPage: this.pageSize,\r\n pageSizeOptions: [5, 10, 25, 50],\r\n totalRecords: this.groupCount,\r\n };\r\n }\r\n\r\n /** Column schema for the groups data table. */\r\n readonly columnSchema: TableColumnSchema[] = [\r\n {\r\n id: 1,\r\n columnDef: 'group',\r\n heading: this.texts?.columns?.group,\r\n // LINK so the group name is a clickable link that opens the group.\r\n columnType: TableColumnType.LINK,\r\n cellData: (row: GroupRow) => row.group,\r\n },\r\n {\r\n id: 2,\r\n columnDef: 'type',\r\n heading: this.texts?.columns?.type,\r\n columnType: TableColumnType.TEXT,\r\n cellData: (row: GroupRow) => row.type || this.texts?.emptyValue,\r\n },\r\n {\r\n id: 3,\r\n columnDef: 'officerRole',\r\n heading: this.texts?.columns?.officerRole,\r\n columnType: TableColumnType.TEXT,\r\n // \"-\" placeholder when the user holds no officer role (matches the design).\r\n cellData: (row: GroupRow) => row.officerRole || this.texts?.emptyValue,\r\n },\r\n {\r\n id: 4,\r\n columnDef: 'affiliation',\r\n heading: this.texts?.columns?.affiliation,\r\n columnType: TableColumnType.TEXT,\r\n cellData: (row: GroupRow) => row.affiliation || this.texts?.emptyValue,\r\n },\r\n {\r\n id: 5,\r\n columnDef: 'memberLevel',\r\n heading: this.texts?.columns?.memberLevel,\r\n columnType: TableColumnType.TEXT,\r\n cellData: (row: GroupRow) => row.memberLevel,\r\n // Render the member level as a colored pill via the data-table's inline\r\n // badge; green for voting-type levels, amber for the rest (e.g. Observer).\r\n showInlineBadge: (row: GroupRow) => !!row.memberLevel,\r\n inlineBadgeText: (row: GroupRow) => row.memberLevel,\r\n inlineBadgeClass: (row: GroupRow) => this.resolveBadgeClass(row.memberLevel),\r\n },\r\n ];\r\n\r\n /**\r\n * Toggles the card's expanded/collapsed state (table visibility).\r\n * @memberof YourGroupsComponent\r\n */\r\n onToggleExpand(): void {\r\n this.isExpanded = !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 * Emits the selected group's id from the data-table link click.\r\n * @param {{ row: GroupRow }} event - The data-table link-click payload.\r\n * @memberof YourGroupsComponent\r\n */\r\n onGroupLinkClick(event: { row: GroupRow }): void {\r\n const groupId = event?.row?.groupId;\r\n if (groupId) {\r\n this.groupSelected.emit(groupId);\r\n }\r\n }\r\n\r\n /**\r\n * Re-emits the paginator change as a {@link PageChange}.\r\n * @param {PageEvent} event - The Material paginator event.\r\n * @memberof YourGroupsComponent\r\n */\r\n onPageChange(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 pill CSS class for a member level: the configured \"success\"\r\n * (green) class for voting-type levels, otherwise the \"warning\" (amber) class.\r\n * @param {string} memberLevel - The member level label.\r\n * @return {string}\r\n * @memberof YourGroupsComponent\r\n */\r\n private resolveBadgeClass(memberLevel: string): string {\r\n const badgeTexts = this.texts?.memberLevelBadge;\r\n const isVoting = (memberLevel ?? '')\r\n .toLowerCase()\r\n .includes('voting');\r\n return isVoting ? badgeTexts?.votingMember : badgeTexts?.default;\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 <p class=\"ieeesa-your-groups__count m-0\">\r\n {{ groupCount }} {{ texts?.countSuffix }}\r\n </p>\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 expanded. Loader / error / empty / table are mutually\r\n exclusive, driven by sectionState. -->\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 <ieeesa-data-table\r\n *ngIf=\"sectionState === sectionStates.LOADED\"\r\n class=\"ieeesa-your-groups__table\"\r\n [tableDataInfo]=\"groups\"\r\n [columnSchemaInfo]=\"columnSchema\"\r\n [tableActions]=\"tableActions\"\r\n [paginatorConfig]=\"paginatorConfig\"\r\n [pageIndex]=\"pageIndex\"\r\n [pageSize]=\"pageSize\"\r\n (columnDataOnRowLinkClick)=\"onGroupLinkClick($event)\"\r\n (paginationChange)=\"onPageChange($event)\"\r\n ></ieeesa-data-table>\r\n </div>\r\n</section>\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 { UpcomingEvent } from '../models/upcoming-event.model';\r\nimport {\r\n DashboardGroupsMock,\r\n DashboardUpcomingEventsMock,\r\n} from '../assets/dashboard-mock';\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 and groups loads currently return annotated mock data\r\n * because their endpoints are not yet available; the attendance actions compose\r\n * the pure reducers from `attendance-reducers.ts` so the displayed\r\n * `AttendanceState` only advances on a successful resolution and the prior\r\n * 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, driving the upcoming 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 and seeds the\r\n * per-meeting attendance-state map from the loaded meetings.\r\n *\r\n * TODO: Replace mock with real API call when BE is ready\r\n * @return {Observable<DashboardListResponse<UpcomingEvent[]>>} The upcoming-events response envelope.\r\n * @memberof DashboardService\r\n */\r\n loadUpcomingEvents(): Observable<DashboardListResponse<UpcomingEvent[]>> {\r\n this.upcomingState.next(DashboardSectionState.LOADING);\r\n // TODO: Replace mock with real API call when BE is ready\r\n const response$: Observable<DashboardListResponse<UpcomingEvent[]>> = of({\r\n status: true,\r\n body: DashboardUpcomingEventsMock,\r\n });\r\n return response$.pipe(\r\n map((response) => {\r\n const events = response?.body ?? [];\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 * 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<GroupRow[]>> {\r\n this.groupsState.next(DashboardSectionState.LOADING);\r\n // TODO: Replace mock with real API call when BE is ready\r\n const response$: Observable<DashboardListResponse<GroupRow[]>> = of({\r\n status: true,\r\n body: DashboardGroupsMock,\r\n });\r\n return response$.pipe(\r\n map((response) => {\r\n const groups = response?.body ?? [];\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 * 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 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","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 EventEmitter,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n Output,\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 /**\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. */\r\n groupsPageSize = 10;\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, emitting the navigation intent\r\n * for the matching section so the host app routes to it: MEETINGS →\r\n * `viewAllEvents` (/events-and-meetings/view-events-meetings-list), GROUPS →\r\n * `viewAllGroups` (/groups).\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 path =\r\n target === DashboardJumpTarget.MEETINGS\r\n ? this.activeRouteConfig.viewAllEvents\r\n : this.activeRouteConfig.viewAllGroups;\r\n this.emitNavigation(path);\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 * 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 [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 class=\"ieeesa-dashboard__upcoming\"\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 ></ieeesa-upcoming-meetings-events>\r\n\r\n <ieeesa-your-groups\r\n [groups]=\"groups | slice: (groupsPageIndex * groupsPageSize) : ((groupsPageIndex + 1) * groupsPageSize)\"\r\n [sectionState]=\"groupsState\"\r\n [totalGroups]=\"groups.length\"\r\n [pageIndex]=\"groupsPageIndex\"\r\n [pageSize]=\"groupsPageSize\"\r\n (groupSelected)=\"onGroupSelected($event)\"\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","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 // 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\r\n // the 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 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","/*\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/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":["constants","i1","i1.DashboardService","i2.UserPermissionsService","i4","i5"],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@ieeesa-npm/dashboard" />
5
+ export * from './public-api';
@@ -0,0 +1,31 @@
1
+ import { GroupRow } from '../models/group-row.model';
2
+ import { MeetingRow } from '../models/meeting-row.model';
3
+ import { UpcomingEvent } from '../models/upcoming-event.model';
4
+ /**
5
+ * Mock upcoming-events + groups fixtures for the dashboard library.
6
+ *
7
+ * These exercise the key presentation edge cases:
8
+ * - empty/undefined `groupOrCommittee` and `roomOrLocation` (empty-field placeholder)
9
+ * - a mix of `CURRENTLY_ATTENDING` / `NOT_ATTENDING` attendance states
10
+ * - events with many meetings so per-card pagination is exercised
11
+ *
12
+ * TODO: Replace mock with real API call when BE is ready
13
+ */
14
+ export declare const DashboardUpcomingEventsMock: UpcomingEvent[];
15
+ /**
16
+ * Mock a single meeting row with an empty `meetingId` to exercise the
17
+ * non-actionable (empty/undefined id) path in the meeting row component.
18
+ *
19
+ * TODO: Replace mock with real API call when BE is ready
20
+ */
21
+ export declare const DashboardNonActionableMeetingMock: MeetingRow;
22
+ /**
23
+ * Mock groups fixtures for the dashboard "Your Groups" section.
24
+ *
25
+ * Includes rows with missing optional fields (`type`, `officerRole`,
26
+ * `affiliation`) and a spread of member levels so the member-level badge
27
+ * colour map and empty-field placeholders are exercised.
28
+ *
29
+ * TODO: Replace mock with real API call when BE is ready
30
+ */
31
+ export declare const DashboardGroupsMock: GroupRow[];
@@ -0,0 +1,2 @@
1
+ import { DashboardRouteConfig } from '../models/dashboard-route-config.model';
2
+ export declare const DashboardRoutePathsMock: DashboardRouteConfig;
@@ -0,0 +1,2 @@
1
+ import { UserPermission } from '@ieeesa-npm/models';
2
+ export declare const DashboardUserPermissionsMock: UserPermission[];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Luxon format tokens used across the dashboard library for rendering
3
+ * event/meeting dates, times, and timezones.
4
+ *
5
+ * These tokens follow the luxon `DateTime.toFormat()` convention
6
+ * (NOT moment). New code in this library must use luxon exclusively.
7
+ *
8
+ * @see https://moment.github.io/luxon/#/formatting?id=table-of-tokens
9
+ */
10
+ export declare const DateFormats: {
11
+ /** ISO date used for request payloads, e.g. 2025-03-14. */
12
+ requestPayloadFormat: string;
13
+ /** ISO date-time used for request payloads, e.g. 2025-03-14T09:30:00. */
14
+ requestPayloadDateTimeFormat: string;
15
+ /** Human-readable date for display, e.g. 14 Mar 2025. */
16
+ displayFormat: string;
17
+ /** Human-readable long date for display, e.g. 14 March 2025. */
18
+ displayLongFormat: string;
19
+ /** 24-hour time for display, e.g. 09:30. */
20
+ timeFormat: string;
21
+ /** 12-hour time with meridiem for display, e.g. 9:30 AM. */
22
+ timeMeridiemFormat: string;
23
+ /** Short timezone abbreviation for display, e.g. EST. */
24
+ timezoneFormat: string;
25
+ /** Long timezone name for display, e.g. Eastern Standard Time. */
26
+ timezoneLongFormat: string;
27
+ };