@fhss-web-team/frontend-utils 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # FrontendUtils
2
2
 
3
- `@fhss-web-team/frontend-utils` is a shared Angular library for reusable components, services, and signals used across FHSS websites.
3
+ A shared Angular library for reusable components, services, and signals used across FHSS websites.
4
4
 
5
5
  This package is designed for use in Angular applications and includes integration with Keycloak for authentication.
6
6
 
@@ -12,199 +12,132 @@ Install the package and its required peer dependencies:
12
12
  npm install @fhss-web-team/frontend-utils
13
13
  ```
14
14
 
15
+
15
16
  # Documentation
17
+
16
18
  - [Components](#components)
19
+ - [Pages](#pages)
17
20
  - [Services](#services)
21
+ - [Guards](#guards)
18
22
  - [Signals](#signals)
23
+ - [Config](#config)
19
24
 
20
- ## Components
21
-
22
- This directory contains reusable Angular components designed to streamline development and maintain consistency across BYU websites.
23
-
24
- ### BYU Header
25
- This is the header displayed on all BYU websites. It displays the BYU logo, site title, breadcrumbs, and navigation menu.
26
-
27
- #### Features:
28
- - **Logo**: Displays the BYU logo.
29
- - **Title and Subtitle**: Configurable links for the site title and subtitle.
30
- - **Breadcrumbs**: Displays a breadcrumb trail for navigation.
31
- - **Navigation Menu**: Supports both simple links and dropdown menus.
32
- - **Authentication**: Integrates with the [auth service](#auth) to display user information and provide sign-in/sign-out functionality.
33
-
34
- #### Configuration:
35
- The header is configured using a `HeaderConfig` object. Below is the structure:
36
-
37
- ```typescript
38
- type HeaderLink = {
39
- text: string;
40
- path: string;
41
- };
42
-
43
- type HeaderMenu = HeaderLink | {
44
- text: string;
45
- items: HeaderLink[];
46
- };
47
-
48
- export type HeaderConfig = {
49
- title: HeaderLink;
50
- subtitle?: HeaderLink;
51
- breadcrumbs?: HeaderLink[];
52
- menu?: HeaderMenu[];
53
- };
54
- ```
55
-
56
- #### Usage:
57
- Pass the `HeaderConfig` object to the `byu-header` component:
58
-
59
- ```html
60
- <byu-header [config]="headerConfig"></byu-header>
61
- ```
62
-
63
- Example `HeaderConfig`:
64
-
65
- ```typescript
66
- const headerConfig = {
67
- title: { text: 'Home', path: '/' },
68
- subtitle: { text: 'About Us', path: '/about' },
69
- breadcrumbs: [
70
- { text: 'Home', path: '/' },
71
- { text: 'Section', path: '/section' }
72
- ],
73
- menu: [
74
- { text: 'Services', path: '/services' },
75
- {
76
- text: 'More',
77
- items: [
78
- { text: 'Contact', path: '/contact' },
79
- { text: 'Help', path: '/help' }
80
- ]
81
- }
82
- ]
83
- };
84
- ```
85
-
86
- ---
87
-
88
- ### BYU Footer
89
- This is the footer displayed on all BYU websites. It provides essential information and links to comply with legal and institutional requirements.
90
-
91
- #### Features:
92
- - **University Name**: Displays "Brigham Young University" with a link to the main BYU website.
93
- - **Address**: Displays the university's address.
94
- - **Copyright Notice**: Automatically updates the year to the current year.
95
- - **Privacy Links**: Includes links to the Privacy Notice and Cookie Preferences pages.
96
-
97
- #### Usage:
98
- Add the `byu-footer` component to your template:
99
-
100
- ```html
101
- <byu-footer />
102
- ```
103
-
104
- The footer does not require any configuration and is ready to use out of the box.
105
25
 
106
- ---
107
-
108
- ### User Management Table
109
- This component provides a table for managing user data, including search, filtering, sorting, and pagination functionalities. It will use the site's backend's `/api/user-management/` route.
110
-
111
- #### Features:
112
- - **Search**: Allows searching for users by their NetID or other attributes.
113
- - **Filtering**: Supports filtering by account types (e.g., NonBYU, Student, Employee).
114
- - **Sorting**: Columns can be sorted by attributes such as NetID, First Name, Last Name, Account Type, and Created Date.
115
- - **Pagination**: Includes a paginator to navigate through large datasets.
116
- - **Dynamic Data**: Fetches user data dynamically from the server.
117
-
118
- #### Configuration:
119
- The table uses the following signals for configuration:
120
- - `search`: A string for filtering users by search terms.
121
- - `accountTypes`: An array of account types to filter users.
122
- - `sortBy`: The column to sort by (e.g., `netId`, `preferredFirstName`).
123
- - `sortDirection`: The sorting direction (`asc` or `desc`).
124
- - `pageCount`: The number of rows per page.
125
- - `pageOffset`: The offset for pagination.
126
- - `createdAfter` and `createdBefore`: Filtering by creationg date
127
-
128
- #### Usage:
129
- Add the `app-user-management` component to your template:
130
-
131
- ```html
132
- <app-user-management />
133
- ```
134
-
135
- The component automatically handles data fetching and UI updates based on user interactions.
26
+ ## Components
136
27
 
28
+ Reusable Angular components to streamline development and maintain consistency across BYU/FHSS websites.
29
+
30
+ ### BYU Header (`byu-header`)
31
+ - **Purpose:** Displays the BYU logo, site title, breadcrumbs, and navigation menu.
32
+ - **Config:** Accepts a `HeaderConfig` object with `title`, `subtitle`, `breadcrumbs`, and `menu` (supports dropdowns).
33
+ - **Auth Integration:** Uses `AuthService` for user info and sign-in/out.
34
+ - **Usage:**
35
+ ```html
36
+ <byu-header [config]="headerConfig"></byu-header>
37
+ ```
38
+
39
+ Example `HeaderConfig`:
40
+ ```typescript
41
+ const headerConfig = {
42
+ title: { text: 'Home', path: '/' },
43
+ subtitle: { text: 'About Us', path: '/about' },
44
+ breadcrumbs: [
45
+ { text: 'Home', path: '/' },
46
+ { text: 'Section', path: '/section' }
47
+ ],
48
+ menu: [
49
+ { text: 'Services', path: '/services' },
50
+ {
51
+ text: 'More',
52
+ items: [
53
+ { text: 'Contact', path: '/contact' },
54
+ { text: 'Help', path: '/help' }
55
+ ]
56
+ }
57
+ ]
58
+ };
59
+ ```
60
+
61
+ ### BYU Footer (`byu-footer`)
62
+ - **Purpose:** Displays BYU name, address, copyright, and privacy links.
63
+ - **Features:** Year auto-updates.
64
+ - **Usage:**
65
+ ```html
66
+ <byu-footer />
67
+ ```
68
+
69
+ ### FHSS Table (`fhss-table`)
70
+ - **Purpose:** Generic, configurable data table for displaying and interacting with tabular data.
71
+ - **Features:** Search, filter, sort, pagination, row selection/click, dynamic columns, and integration with tRPC resources.
72
+ - **Config:** Accepts a `FhssTableConfig` object (see `fhss-table.types.ts`).
73
+ - **Usage:**
74
+ ```html
75
+ <fhss-table [config]="tableConfig"></fhss-table>
76
+ ```
77
+
78
+
79
+ ## Pages
80
+
81
+ - **Auth Callback:** Handles post-login redirect and provisioning.
82
+ - **Auth Error, Forbidden, Not Found:** Simple pages for error and access control, using BYU header/footer.
137
83
 
138
84
 
139
85
  ## Services
140
86
 
141
- The services in this library provide reusable logic and utilities to simplify common tasks such as authentication, data fetching, and state management. They are designed to integrate seamlessly with Angular applications and follow best practices for dependency injection and reactive programming.
142
-
143
- ### Auth
144
- Wraps the `keycloak-angular` service to provide a simplified interface for authentication and authorization.
87
+ ### AuthService
88
+ - **Purpose:** Wraps Keycloak for authentication and authorization.
89
+ - **Features:**
90
+ - Signals for authentication state, tokens, user info, roles.
91
+ - Methods: `login`, `logout`, `handleAuthCallback`, `getRoleHomeRoute`.
92
+ - Integrates with Angular signals for reactivity.
145
93
 
146
- #### Features:
147
- - **Login and Logout**: Methods to handle user login and logout.
148
- - **Authentication Signals**: Signals to track authentication status, tokens, and user information.
149
- - **Token Management**: Provides access to tokens (e.g., `token`, `idToken`, `refreshToken`) and their parsed forms.
150
- - **Role and Access Management**: Signals for realm and resource roles.
151
- - **Time Skew and Configuration**: Signals for Keycloak configuration properties like `timeSkew`, `responseMode`, and `flow`.
152
94
 
95
+ ## Guards
153
96
 
97
+ - **authGuard:** Protects routes, redirects to login if not authenticated.
98
+ - **roleGuardFactory:** Protects routes by required roles, redirects to `/forbidden` if unauthorized.
154
99
 
155
100
 
156
101
  ## Signals
157
102
 
158
103
  ### fetchSignal
159
- The `fetchSignal` helper provides a reactive way to perform HTTP requests in Angular applications. It supports various HTTP methods and automatically tracks dependencies for reactivity.
160
-
161
- #### Features:
162
- - **Reactive Requests**: Automatically updates when input signals change.
163
- - **Support for Multiple Methods**: Includes `GET`, `POST`, `PUT`, `PATCH`, and `DELETE`.
164
- - **Response Parsing**: Supports JSON, text, Blob, and ArrayBuffer responses.
165
- - **Error Handling**: Tracks errors and status codes reactively.
166
- - **Auto-Refresh**: Automatically refreshes requests when dependencies change.
167
-
168
- #### Usage:
169
- ```typescript
170
- import { fetchSignal } from '@fhss-web-team/frontend-utils';
171
-
172
- // Example: Reactive GET request
173
- const request = () => ({
174
- url: '/api/data',
175
- params: { filter: 'active' },
176
- });
177
- const dataSignal = fetchSignal.json(request, true);
178
-
179
- // Access reactive properties
180
- dataSignal.value(); // Current response value
181
- dataSignal.isLoading(); // Loading state
182
- dataSignal.error(); // Error details
183
- dataSignal.refresh(); // Manually refresh the request
184
- ```
185
-
186
- ---
104
+ - **Purpose:** Reactive HTTP requests (GET, POST, etc.) with Angular signals.
105
+ - **Features:** Auto-refresh, error/status tracking, supports JSON/text/blob, manual refresh.
106
+ - **Usage:**
107
+ ```typescript
108
+ import { fetchSignal } from '@fhss-web-team/frontend-utils';
109
+ // Example: Reactive GET request
110
+ const request = () => ({
111
+ url: '/api/data',
112
+ params: { filter: 'active' },
113
+ });
114
+ const dataSignal = fetchSignal.json(request, true);
115
+ // Access reactive properties
116
+ dataSignal.value(); // Current response value
117
+ dataSignal.isLoading(); // Loading state
118
+ dataSignal.error(); // Error details
119
+ dataSignal.refresh(); // Manually refresh the request
120
+ ```
187
121
 
188
122
  ### debounced
189
- The `debounced` helper creates a debounced version of a signal, delaying updates until after a specified wait time.
190
-
191
- #### Features:
192
- - **Debounced Updates**: Reduces the frequency of updates to a signal.
193
- - **Customizable Delay**: Specify the debounce delay in milliseconds.
194
-
195
- #### Usage:
196
- ```typescript
197
- import { signal } from '@angular/core';
198
- import { debounced } from '@fhss-web-team/frontend-utils';
199
-
200
- // Example: Debounced search input
201
- const searchInput = signal('');
202
- const debouncedSearch = debounced(searchInput, 300);
203
-
204
- // Update the input signal
205
- searchInput.set('new search term');
206
-
207
- // The debounced signal updates after 300ms
208
- debouncedSearch(); // 'new search term' (after delay)
209
- ```
123
+ - **Purpose:** Debounced version of a signal, useful for search inputs.
124
+ - **Usage:**
125
+ ```typescript
126
+ import { signal } from '@angular/core';
127
+ import { debounced } from '@fhss-web-team/frontend-utils';
128
+ const searchInput = signal('');
129
+ const debouncedSearch = debounced(searchInput, 300);
130
+ searchInput.set('new search term');
131
+ // The debounced signal updates after 300ms
132
+ debouncedSearch(); // 'new search term' (after delay)
133
+ ```
134
+
135
+ ### trpcResource
136
+ - **Purpose:** Reactive resource for tRPC procedures, with auto-refresh and error/loading signals.
137
+
138
+
139
+ ## Config
140
+
141
+ - **FHSS_CONFIG:** Angular injection token for library-wide config (e.g., role home pages).
142
+ - **provideFhss:** Helper to provide config in your app.
210
143
 
@@ -436,7 +436,7 @@ class FhssTableComponent {
436
436
  return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;
437
437
  }
438
438
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FhssTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
439
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FhssTableComponent, isStandalone: true, selector: "fhss-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, miscParams: { classPropertyName: "miscParams", publicName: "miscParams", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValues: "selectedValuesChange" }, ngImport: i0, template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field subscriptSizing=\"dynamic\">\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd}.mat-column-table-checkbox-column{background:#686868}.no-data{width:fit-content;margin:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i10.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
439
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FhssTableComponent, isStandalone: true, selector: "fhss-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, miscParams: { classPropertyName: "miscParams", publicName: "miscParams", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValues: "selectedValuesChange" }, ngImport: i0, template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\" subscriptSizing=\"dynamic\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" >\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd;padding:10px 0}.mat-column-table-checkbox-column{width:fit-content}.no-data{width:fit-content;margin:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i10.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
440
440
  }
441
441
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FhssTableComponent, decorators: [{
442
442
  type: Component,
@@ -451,7 +451,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
451
451
  MatIconModule,
452
452
  MatRippleModule,
453
453
  MatCheckboxModule,
454
- ], template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field subscriptSizing=\"dynamic\">\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd}.mat-column-table-checkbox-column{background:#686868}.no-data{width:fit-content;margin:auto}\n"] }]
454
+ ], template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\" subscriptSizing=\"dynamic\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" >\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd;padding:10px 0}.mat-column-table-checkbox-column{width:fit-content}.no-data{width:fit-content;margin:auto}\n"] }]
455
455
  }] });
456
456
 
457
457
  const provideFhss = (config) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"fhss-web-team-frontend-utils.mjs","sources":["../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.ts","../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.html","../../../projects/frontend-utils/src/lib/config/lib.config.ts","../../../projects/frontend-utils/src/lib/services/auth/auth.service.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.html","../../../projects/frontend-utils/src/lib/signals/trpcResource/trpcResource.ts","../../../projects/frontend-utils/src/lib/signals/debounced/debounced.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.types.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.html","../../../projects/frontend-utils/src/lib/config/utils.config.ts","../../../projects/frontend-utils/src/lib/guards/auth/auth.guard.ts","../../../projects/frontend-utils/src/lib/guards/role/role.guard.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.html","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.html","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.ts","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.html","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.ts","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.html","../../../projects/frontend-utils/src/lib/signals/fetch-signal/fetch-signal.ts","../../../projects/frontend-utils/src/public-api.ts","../../../projects/frontend-utils/src/fhss-web-team-frontend-utils.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'byu-footer',\n imports: [],\n templateUrl: './byu-footer.component.html',\n styleUrl: './byu-footer.component.scss'\n})\nexport class ByuFooterComponent {\n currentYear: number = new Date().getFullYear(); // Automatically updates the year\n}\n","<footer>\n <p class=\"title\"><a href=\"https://www.byu.edu/\">BRIGHAM YOUNG UNIVERSITY</a></p>\n <p>Provo, UT 84602, USA | © {{ currentYear }} All rights reserved.</p>\n <p>\n <a href=\"https://privacy.byu.edu/privacy-notice\">Privacy Notice</a> |\n <a href=\"https://privacy.byu.edu/cookie-prefs\">Cookie Preferences</a>\n </p>\n</footer>\n \n\n","import { InjectionToken } from '@angular/core';\n\nexport const FHSS_CONFIG = new InjectionToken<FhssConfig>('FHSS_CONFIG');\n\nexport interface FhssConfig {\n roleHomePages: Record<string, string>;\n}\n","import {\n Injectable,\n inject,\n computed,\n afterNextRender,\n effect,\n Injector,\n signal,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport {\n KEYCLOAK_EVENT_SIGNAL,\n KeycloakEventType,\n ReadyArgs,\n typeEventArgs,\n} from 'keycloak-angular';\nimport Keycloak, {\n KeycloakFlow,\n KeycloakResourceAccess,\n KeycloakResponseMode,\n KeycloakResponseType,\n KeycloakRoles,\n KeycloakTokenParsed,\n} from 'keycloak-js';\nimport { FHSS_CONFIG } from '../../config/lib.config';\n\n@Injectable({\n providedIn: 'root',\n})\n/**\n * AuthService provides a wrapper around the Keycloak JavaScript adapter, exposing its properties and methods\n * as Angular signals for reactive programming. It simplifies authentication, token management, and role-based access control.\n */\nexport class AuthService {\n private keycloak = inject(Keycloak);\n private keycloakSignal = inject(KEYCLOAK_EVENT_SIGNAL);\n private router = inject(Router);\n private config = inject(FHSS_CONFIG);\n\n private readonly nextUriKey = 'nextUri';\n private readonly injector = inject(Injector);\n\n /**\n * Signal indicating whether the user is authenticated.\n * Returns `true` if authenticated, `false` otherwise.\n */\n authenticated = signal(false);\n\n constructor() {\n afterNextRender(() => {\n effect(\n () => {\n const kcEvent = this.keycloakSignal();\n if (kcEvent.type === KeycloakEventType.Ready) {\n this.authenticated.set(typeEventArgs<ReadyArgs>(kcEvent.args));\n }\n if (kcEvent.type === KeycloakEventType.AuthLogout) {\n this.authenticated.set(false);\n }\n },\n { injector: this.injector },\n );\n });\n }\n\n /**\n * Initiates the login process. Optionally stores a route to redirect to after login.\n * @param nextUri - The route to navigate to after successful login.\n */\n login = (nextUri?: string) => {\n if (nextUri) {\n sessionStorage.setItem(this.nextUriKey, nextUri);\n }\n this.keycloak.login({\n redirectUri: window.location.origin + '/auth-callback',\n });\n };\n\n /**\n * Gets the user's role home route\n *\n * @returns the user's role's home route,\n * or null if there isn't one\n */\n getRoleHomeRoute = () => {\n if (!this.authenticated()) return null;\n\n const userRoles = new Set(this.realmAccess()?.roles);\n for (const role in this.config.roleHomePages) {\n if (userRoles.has(role)) {\n return this.config.roleHomePages[role];\n }\n }\n return null;\n };\n\n /**\n * Handles user provisioning.\n *\n * @returns the uri to which the application should navigate\n */\n handleAuthCallback = async (): Promise<void> => {\n try {\n const savedRoute = sessionStorage.getItem(this.nextUriKey);\n sessionStorage.removeItem(this.nextUriKey);\n\n if (!this.authenticated()) {\n this.router.navigate(['/']);\n return;\n }\n\n const res = await fetch(window.location.origin + '/api/auth/callback', {\n headers: { Authorization: this.bearerToken() ?? '' },\n });\n\n if (!res.ok) throw new Error('User provisioning failed');\n const customRoute: string | null =\n res.status === 200 ? (await res.json()).next : null;\n\n const userHomeRoute = this.getRoleHomeRoute();\n\n const nextRoute = customRoute ?? savedRoute ?? userHomeRoute ?? '/';\n this.router.navigate([nextRoute]);\n } catch (err) {\n console.error(err);\n this.logout('/auth-error');\n }\n };\n\n /**\n * Logs the user out of the application.\n */\n logout = (nextUri?: string) =>\n this.keycloak.logout({\n redirectUri: window.location.origin + (nextUri ?? '/'),\n });\n\n /**\n * Signal for the base64-encoded token used in the `Authorization` header.\n */\n token = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.token;\n });\n\n /**\n * Signal for the Bearer token, prefixed with \"Bearer \".\n */\n bearerToken = computed<string | undefined>(() =>\n this.token() ? 'Bearer ' + this.token() : undefined,\n );\n\n /**\n * Signal for the parsed token as a JavaScript object.\n */\n tokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.tokenParsed;\n });\n\n /**\n * Signal for the user ID (Keycloak subject).\n */\n userId = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.subject;\n });\n\n /**\n * Signal for the base64-encoded ID token.\n */\n idToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idToken;\n });\n\n /**\n * Signal for the parsed ID token as a JavaScript object.\n */\n idTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idTokenParsed;\n });\n\n /**\n * Signal for the realm roles associated with the token.\n */\n realmAccess = computed<KeycloakRoles | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.realmAccess;\n });\n\n /**\n * Signal for the resource roles associated with the token.\n */\n resourceAccess = computed<KeycloakResourceAccess | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.resourceAccess;\n });\n\n /**\n * Signal for the base64-encoded refresh token.\n */\n refreshToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshToken;\n });\n\n /**\n * Signal for the parsed refresh token as a JavaScript object.\n */\n refreshTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshTokenParsed;\n });\n\n /**\n * Signal for the estimated time difference between the browser and Keycloak server in seconds.\n */\n timeSkew = computed<number | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.timeSkew;\n });\n\n /**\n * Signal for the response mode passed during initialization.\n */\n responseMode = computed<KeycloakResponseMode | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseMode;\n });\n\n /**\n * Signal for the flow type used during initialization.\n */\n flow = computed<KeycloakFlow | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.flow;\n });\n\n /**\n * Signal for the response type sent to Keycloak during login requests.\n */\n responseType = computed<KeycloakResponseType | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseType;\n });\n}\n","import { Component, input, inject } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\ntype HeaderLink = {\n text: string;\n path: string;\n};\n\n// A HeaderMenu can be either a simple link with path,\n// OR a menu group with nested items\ntype HeaderMenu = HeaderLink | {\n text: string;\n items: HeaderLink[];\n}\n\nexport type HeaderConfig = {\n title: HeaderLink;\n subtitle?: HeaderLink;\n breadcrumbs?: HeaderLink[];\n menu?: HeaderMenu[];\n}\n\n@Component({\n selector: 'byu-header',\n imports: [RouterModule],\n templateUrl: './byu-header.component.html',\n styleUrl: './byu-header.component.scss'\n})\nexport class ByuHeaderComponent {\n auth = inject(AuthService)\n config = input<HeaderConfig>();\n\n isHeaderLink(item: HeaderMenu): item is HeaderLink {\n return 'path' in item;\n }\n\n // Track which dropdown is open (null means none are open)\n openDropdownText: string | null = null;\n \n // Toggle function — if clicking the same dropdown, close it; otherwise open it\n toggleDropdown(text: string) {\n this.openDropdownText = this.openDropdownText === text ? null : text;\n }\n \n // Check if a given dropdown is currently open\n isOpen(text: string): boolean {\n return this.openDropdownText === text;\n }\n}\n","<header>\n <div class=\"top\" >\n <img class=\"logo\" src=\"/BYU_monogram_white@2x.png\" alt=\"BYU\">\n <div class=\"titles\"> \n <div class=\"breadcrumbs\">\n @for (breadcrumb of config()?.breadcrumbs; track breadcrumb.text){\n <a [href]=\"breadcrumb.path\" >{{ breadcrumb.text }}</a>\n }\n </div>\n <a [routerLink]=\"config()?.title?.path\" class=\"title\">{{ config()?.title?.text }}</a>\n <a [routerLink]=\"config()?.subtitle?.path\" class=\"subtitle\">{{ config()?.subtitle?.text }}</a>\n </div>\n <div class=\"signin\">\n <p>{{ this.auth.tokenParsed()?.['given_name'] ?? '' }}</p>\n <svg class=\"signin-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n <path fill=\"currentcolor\" d=\"M50 95c-26 0-34-18-34-18 3-12 8-18 17-18 5 5 10 7 17 7s12-2 17-7c9 0 14 6 17 18 0 0-7 18-34 18z\"></path>\n <circle cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"currentcolor\" stroke-width=\"10\"></circle>\n <circle fill=\"currentcolor\" cx=\"50\" cy=\"40\" r=\"20\"></circle>\n </svg>\n @if (auth.authenticated()) {\n <a class=\"signin-link\" (click)=\"auth.logout()\">Sign Out</a>\n } @else {\n <a class=\"signin-link\" (click)=\"auth.login()\">Sign In</a>\n }\n </div>\n </div>\n <div class=\"bottom\">\n <nav>\n @for (menuItem of config()?.menu; track menuItem.text){\n @if (isHeaderLink(menuItem)) {\n <li class = \"nav-item\">\n <a class=\"nav-item-content\" [routerLink]=\"menuItem.path\">{{ menuItem.text }}</a>\n </li>\n } @else {\n <li class=\"nav-item dropdown\" (click)=\"toggleDropdown(menuItem.text)\">\n <div class=\"nav-item-content\" >{{ menuItem.text }}</div>\n @if (openDropdownText === menuItem.text) {\n <ul class = \"dropdown-item-menu\"> \n @for(dropItem of menuItem.items; track dropItem.text){\n <li class = \"dropdown-item\">\n <a class=\"dropdown-item-content\" [routerLink]=\"dropItem.path\">{{ dropItem.text }}</a>\n </li>\n }\n </ul>\n }\n </li>\n }\n }\n </nav>\n </div>\n</header>\n","import { computed, effect, EffectRef, inject, Injector, signal } from \"@angular/core\";\nimport { isTRPCClientError, Resolver } from \"@trpc/client\";\nimport { ResolverDef, TrpcResource ,TrpcResourceOptions } from \"./trpcResource.types\";\n\nfunction trpcResource<TDef extends ResolverDef>(procedure: Resolver<TDef>, input: () => TDef['input'], options?: TrpcResourceOptions<TDef['output']>): TrpcResource<TDef> {\n const currentInput = computed(input);\n\n const value = signal<TDef['output'] | undefined>(options?.defaultValue, { equal: options?.equal });\n const error = signal<TDef['errorShape'] | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n\n if (options?.autoRefresh) {\n const effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n // refresh reads currentInput which triggers the effect\n refresh(controller.signal, true);\n }, { injector: options?.injector || inject(Injector)});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort: boolean = true,\n ) => {\n // Reset signals for a fresh request.\n isLoading.set(true);\n error.set(undefined);\n\n try {\n value.set(await procedure(currentInput(), {\n signal: abortSignal\n }));\n error.set(undefined)\n } catch (err) {\n if (isTRPCClientError(err)) {\n // if the trpc request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.cause?.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n console.error(\"A non-tRPC error has occured on this trpcResource: \", String(err));\n }\n value.set(options?.defaultValue);\n }\n isLoading.set(false);\n }\n\n return {\n value,\n error,\n isLoading,\n refresh\n };\n}\n\nfunction debugTrpcResource<TDef extends ResolverDef>(_trpcResource: TrpcResource<TDef>) {\n return {\n value: _trpcResource.value(),\n error: _trpcResource.error(),\n isLoading: _trpcResource.isLoading(),\n }\n}\n\nexport { debugTrpcResource, trpcResource };","import { effect, signal, Signal } from \"@angular/core\";\n\nexport const debounced = <T>(inputSignal: Signal<T>, wait: number = 400) => {\n const debouncedSignal = signal<T>(inputSignal());\n const setSignal = debounce((value) => debouncedSignal.set(value), wait);\n\n effect(() => {\n setSignal(inputSignal())\n })\n\n return debouncedSignal;\n}\n\nconst debounce = (callback: (...args: any[]) => void, wait: number) => {\n let timeoutId: number | undefined;\n return (...args: any[]) => {\n window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n}","import { Resolver } from '@trpc/client';\nimport { ResolverDef } from '../../signals/trpcResource/trpcResource.types';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\n\nexport type FhssTableConfig<TDef extends ResolverDef> = {\n procedure: Resolver<TDef>;\n columns: {\n [K in keyof TDef['output']['data'][number]]: {\n hide?: boolean;\n header?: string;\n allowSort?: boolean;\n individualFilter?: boolean;\n };\n };\n showSearch?: boolean;\n sorting: {\n defaultSortBy: Extract<keyof TDef['output']['data'][number], string>;\n defaultSortDirection?: 'asc' | 'desc';\n };\n pagination: {\n pageSize: number;\n hideControls?: boolean;\n };\n interaction?:\n | {\n type: 'click';\n onClick: (obj: TDef['output']['data'][number]) => void;\n }\n | {\n type: 'select';\n multi?: boolean;\n };\n};\n\nexport const makeTableConfig = <TDef extends ResolverDef>(\n config: FhssTableConfig<TDef>,\n) => config;\n\nexport type AnyResolver = {\n input: any;\n output: { totalCount: number; data: any[] };\n transformer: any;\n errorShape: {\n code: any;\n message: string;\n data: any;\n };\n};\n\nexport type AnyResource = ReturnType<typeof trpcResource<AnyResolver>>;\n","import {\n Component,\n inject,\n Injector,\n input,\n linkedSignal,\n model,\n OnInit,\n signal,\n} from '@angular/core';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\nimport { debounced } from '../../signals/debounced/debounced';\nimport { FhssTableConfig, AnyResolver, AnyResource } from './fhss-table.types';\nexport { makeTableConfig } from './fhss-table.types';\n\nimport { MatTableModule } from '@angular/material/table';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\nimport { MatInputModule } from '@angular/material/input';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatRippleModule } from '@angular/material/core';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { SelectionModel } from '@angular/cdk/collections';\n\n@Component({\n selector: 'fhss-table',\n imports: [\n MatTableModule,\n MatProgressSpinnerModule,\n MatPaginatorModule,\n MatInputModule,\n FormsModule,\n MatButtonModule,\n MatSortModule,\n MatIconModule,\n MatRippleModule,\n MatCheckboxModule,\n ],\n templateUrl: './fhss-table.component.html',\n styleUrl: './fhss-table.component.scss',\n})\nexport class FhssTableComponent implements OnInit {\n private injector = inject(Injector);\n\n config = input.required<FhssTableConfig<AnyResolver>>();\n miscParams = input<Record<string, any>>({});\n\n columnKeys: string[] = [];\n columnsToDisplay: string[] = [];\n selection: SelectionModel<any> | undefined;\n selectedValues = model<any[]>([]);\n\n dataResource!: AnyResource;\n\n ngOnInit() {\n const cfg = this.config();\n\n this.columnKeys = Object.keys(cfg.columns);\n this.columnsToDisplay = this.columnKeys.filter((k) => !cfg.columns[k].hide);\n\n if (cfg.interaction?.type === 'select') {\n this.columnsToDisplay.unshift('table-checkbox-column');\n this.selection = new SelectionModel<any>(\n cfg.interaction.multi,\n undefined,\n undefined,\n (o1, o2) => o1.id === o2.id,\n );\n }\n\n this.dataResource = trpcResource(\n this.config().procedure,\n () => ({\n search: this.debouncedSearch(),\n filters: this.debouncedFilters(),\n sort: {\n property: this.sortBy(),\n direction: this.sortDirection(),\n },\n page: {\n size: this.config().pagination.pageSize,\n index: this.pageIndex(),\n },\n ...this.miscParams(),\n }),\n {\n autoRefresh: true,\n injector: this.injector,\n },\n );\n }\n\n search = signal('');\n debouncedSearch = debounced(this.search);\n filters = signal<Record<string, string>>({});\n debouncedFilters = debounced(this.filters);\n\n sortBy = linkedSignal(() => this.config().sorting.defaultSortBy);\n sortDirection = linkedSignal<'asc' | 'desc'>(\n () => this.config().sorting.defaultSortDirection ?? 'asc',\n );\n\n pageIndex = linkedSignal(() => {\n this.search();\n return 0;\n });\n\n onFilterChange(col: string, val: string) {\n this.filters.update((f) => ({ ...f, [col]: val }));\n }\n onPaginationChange(e: PageEvent) {\n this.pageIndex.set(e.pageIndex);\n }\n onSortChange(sort: Sort) {\n this.sortBy.set(sort.active || this.config().sorting.defaultSortBy);\n this.sortDirection.set(\n sort.direction || this.config().sorting.defaultSortDirection || 'asc',\n );\n this.pageIndex.set(0);\n }\n onSelectionChange() {\n this.selectedValues.set(this.selection?.selected ?? []);\n }\n\n onRowClick(row: any) {\n const interaction = this.config().interaction;\n if (!interaction) return;\n\n if (interaction.type === 'click') {\n interaction.onClick(row);\n } else if (interaction.type === 'select') {\n this.selection?.toggle(row);\n }\n this.onSelectionChange();\n }\n\n isAllSelected() {\n if (!this.selection) return false;\n const numSelected = this.selection.selected.length;\n const numRows = this.dataResource.value()?.data?.length ?? 0;\n return numSelected === numRows;\n }\n\n toggleAllRows() {\n if (!this.selection) return;\n if (this.isAllSelected()) {\n this.selection.clear();\n } else {\n this.selection.select(...(this.dataResource.value()?.data ?? []));\n }\n this.onSelectionChange();\n }\n\n checkboxLabel(row?: any): string {\n if (!this.selection) return '';\n if (!row) {\n return `${this.isAllSelected() ? 'deselect' : 'select'} all`;\n }\n return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;\n }\n}\n","<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field subscriptSizing=\"dynamic\">\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n","import { Provider } from \"@angular/core\";\nimport { FHSS_CONFIG, FhssConfig } from \"./lib.config\";\n\nexport const provideFhss = (config: FhssConfig): Provider => ({\n provide: FHSS_CONFIG,\n useValue: config,\n});\n","import { inject } from '@angular/core';\nimport { CanActivateFn } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\n/**\n * This guard checks if the client is authenticated, redirecting to login if not.\n */\nexport const authGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n if(!authService.authenticated()){\n authService.login(state.url);\n return false;\n }\n return true;\n};\n","import { CanActivateFn, RedirectCommand, Router } from '@angular/router';\nimport { FHSS_CONFIG } from '../../config/lib.config';\nimport { AuthService } from '../../services/auth/auth.service';\nimport { inject } from '@angular/core';\n\n/**\n * Generates a guard function to determine if a user has the required roles to access a route.\n *\n * @example\n * ```typescript\n * const routes: Routes = [\n * {\n * path: 'admin',\n * component: AdminPage,\n * canActivate: [roleGuardFactory(Roles.admin)],\n * },\n * ];\n * ```\n */\nexport const roleGuardFactory: (...allowedRoles: string[]) => CanActivateFn = (...allowedRoles) => {\n return (_route, state) => {\n const authService = inject(AuthService);\n const router = inject(Router);\n\n if (!authService.authenticated()) {\n authService.login(state.url);\n return false;\n }\n\n const userRoles = authService.realmAccess()?.roles;\n const hasRole =\n userRoles?.some((role) => allowedRoles.includes(role)) ?? false;\n\n return hasRole || new RedirectCommand(router.parseUrl('/forbidden'));\n };\n};\n","import { Component, inject } from '@angular/core';\nimport { AuthService } from '../../services/auth/auth.service';\n\n@Component({\n selector: 'app-auth-callback',\n imports: [],\n templateUrl: './auth-callback.page.html',\n styleUrl: './auth-callback.page.scss',\n})\nexport class AuthCallbackPage {\n auth = inject(AuthService)\n\n constructor() {\n this.auth.handleAuthCallback();\n }\n}\n","<div class=\"container\">\n <p>Logging you in...</p>\n</div>","import { Component } from '@angular/core';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\nimport { MatButtonModule } from '@angular/material/button';\n\n@Component({\n selector: 'fhss-auth-error',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './auth-error.page.html',\n styleUrl: './auth-error.page.scss'\n})\nexport class AuthErrorPage {\n\n}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/sad-duck.jpg\" alt=\"sad duck\" />\n <h1>Login Failed</h1>\n <p>Something went wrong while trying to log you in.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-forbidden',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './forbidden.page.html',\n styleUrl: './forbidden.page.scss',\n})\nexport class ForbiddenPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/police-duck.jpg\" alt=\"\" />\n <h1>403 - Forbidden</h1>\n <p>You don't have permission to access this page.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-not-found',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './not-found.page.html',\n styleUrl: './not-found.page.scss',\n})\nexport class NotFoundPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/confused-duck.png\" alt=\"\" />\n <h1>404 - Page not found</h1>\n <p>The page you are looking for doesn't exist or it may have moved.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { computed, effect, EffectRef, inject, Injector, signal, untracked } from '@angular/core';\nimport { FetchSignal, FetchSignalFactory, FetchSignalOptions, FetchSignalRequest, FetchSignalStatus, HttpMethod, Json, ResponseTransformer } from './fetch-signal.types';\n\n\n/**\n * Creates a reactive fetch signal.\n *\n * The request function can include Signals for properties. These are unwrapped in the refresh function.\n */\nfunction createFetchSignal<Response, ErrorResponse, RawResponse>(\n request: () => FetchSignalRequest,\n method: HttpMethod,\n transform: ResponseTransformer<Response>,\n options?: FetchSignalOptions<Response, RawResponse>,\n): FetchSignal<Response, ErrorResponse> {\n // Use a computed signal so that any changes to Signals in the request object trigger updates.\n const currentRequest = computed<FetchSignalRequest>(request);\n\n const value = signal<Response | undefined>(options?.defaultValue, { equal: options?.equal });\n const errorResponse = signal<ErrorResponse | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n const statusCode = signal<number | undefined>(undefined);\n const headers = signal<Record<string, string> | undefined>(undefined);\n\n const status = signal<FetchSignalStatus>('idle');\n const error = signal<Error | undefined>(undefined);\n\n const injector = inject(Injector);\n let effectRef: EffectRef | undefined = undefined;\n if (options?.autoRefresh) {\n effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n refresh(controller.signal, true);\n }, { injector: options?.injector || injector});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort?: boolean,\n ) => {\n // if the fetchSignal has been destroyed, do nothing\n if (untracked(status) === 'destroyed') return;\n\n // Reset signals for a fresh request.\n isLoading.set(true);\n errorResponse.set(undefined);\n statusCode.set(undefined);\n headers.set(undefined);\n status.set('loading');\n error.set(undefined);\n\n // Unwrap the current request.\n const req = currentRequest();\n const url = req.url;\n const params = req.params;\n const requestHeaders = req.headers;\n const body = req.body;\n\n // Build URL with query parameters.\n let uri = url;\n if (params) {\n const searchParams = new URLSearchParams();\n for (const key in params) {\n if (params[key] !== undefined)\n searchParams.append(key, String(params[key]));\n }\n uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();\n }\n \n // Filter out undefined header values\n const filteredHeaders = requestHeaders\n ? Object.fromEntries(\n Object.entries(requestHeaders).filter(\n ([, value]) => value !== undefined\n ) as [string, string][]\n )\n : undefined;\n \n try {\n // send the request\n const response = await fetch(uri, {\n method,\n headers: filteredHeaders,\n // Only include a body if one is provided.\n body: body,\n signal: abortSignal,\n });\n\n // set the status code\n statusCode.set(response.status);\n\n // Extract response headers.\n const headersObj: Record<string, string> = {};\n response.headers.forEach((val, key) => {\n headersObj[key] = val;\n });\n headers.set(headersObj);\n\n // if the response is ok, transform the body\n if (response.ok) {\n value.set(await transform(response));\n status.set('resolved');\n } else {\n // try to parse the error as json\n try {\n errorResponse.set(await response.json());\n value.set(undefined);\n status.set('resolved');\n } catch {\n throw new Error('Unable to parse error response.')\n }\n }\n } catch (err: any) {\n if (err instanceof Error) {\n // if the fetch request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n error.set(new Error(String(err)));\n }\n value.set(undefined);\n status.set('error');\n }\n isLoading.set(false);\n };\n\n const destroy = () => {\n // if the fetchSignal has been destroyed, do nothing\n if (status() === 'destroyed') return;\n\n if (effectRef) {\n effectRef.destroy();\n }\n status.set('destroyed');\n value.set(undefined);\n errorResponse.set(undefined);\n isLoading.set(false);\n statusCode.set(undefined);\n headers.set(undefined);\n error.set(undefined);\n }\n\n return {\n value,\n errorResponse,\n isLoading,\n statusCode,\n headers,\n status,\n error,\n refresh,\n destroy\n };\n}\n\n//\n// Helpers for attaching response transforms.\n//\nconst createHelper = <Response, Error>(method: HttpMethod, transform: ResponseTransformer<Response>) =>\n (request: () => FetchSignalRequest, options?: FetchSignalOptions<Response, any>): FetchSignal<Response, Error> =>\n createFetchSignal<Response, Error, any>(request, method, transform, options);\n\n// Transforms\nconst jsonTransformer: ResponseTransformer<any> = (response: Response) => response.json();\nconst textTransformer: ResponseTransformer<string> = (response: Response) => response.text();\nconst blobTransformer: ResponseTransformer<Blob> = (response: Response) => response.blob();\nconst arrayBufferTransformer: ResponseTransformer<ArrayBuffer> = (response: Response) => response.arrayBuffer();\n\n//\n// Build the defaults - GET chain\n//\nconst fetchSignal = createHelper('GET', jsonTransformer) as FetchSignalFactory;\nfetchSignal.json = createHelper('GET', jsonTransformer);\nfetchSignal.text = createHelper('GET', textTransformer);\nfetchSignal.blob = createHelper('GET', blobTransformer);\nfetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the GET chain\n//\nfetchSignal.get = createHelper(\n 'GET',\n jsonTransformer,\n) as FetchSignalFactory['get'];\nfetchSignal.get.json = createHelper('GET', jsonTransformer);\nfetchSignal.get.text = createHelper('GET', textTransformer);\nfetchSignal.get.blob = createHelper('GET', blobTransformer);\nfetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the POST chain.\n//\nfetchSignal.post = createHelper(\n 'POST',\n jsonTransformer,\n) as FetchSignalFactory['post'];\nfetchSignal.post.json = createHelper('POST', jsonTransformer);\nfetchSignal.post.text = createHelper('POST', textTransformer);\nfetchSignal.post.blob = createHelper('POST', blobTransformer);\nfetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);\n\n//\n// Build the PUT chain.\n//\nfetchSignal.put = createHelper(\n 'PUT',\n jsonTransformer,\n) as FetchSignalFactory['put'];\nfetchSignal.put.json = createHelper('PUT', jsonTransformer);\nfetchSignal.put.text = createHelper('PUT', textTransformer);\nfetchSignal.put.blob = createHelper('PUT', blobTransformer);\nfetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);\n\n//\n// Build the PATCH chain.\n//\nfetchSignal.patch = createHelper(\n 'PATCH',\n jsonTransformer,\n) as FetchSignalFactory['patch'];\nfetchSignal.patch.json = createHelper('PATCH', jsonTransformer);\nfetchSignal.patch.text = createHelper('PATCH', textTransformer);\nfetchSignal.patch.blob = createHelper('PATCH', blobTransformer);\nfetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);\n\n//\n// Build the DELETE chain\n//\nfetchSignal.delete = createHelper(\n 'DELETE',\n jsonTransformer,\n) as FetchSignalFactory['delete'];\nfetchSignal.delete.json = createHelper('DELETE', jsonTransformer);\nfetchSignal.delete.text = createHelper('DELETE', textTransformer);\nfetchSignal.delete.blob = createHelper('DELETE', blobTransformer);\nfetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);\n\nexport { fetchSignal };\nexport type { Json };\n\n","/**\n * Components\n */\nexport * from './lib/components/byu-footer/byu-footer.component'\nexport * from './lib/components/byu-header/byu-header.component'\nexport * from './lib/components/fhss-table/fhss-table.component'\n\n/**\n * Config\n */\nexport * from './lib/config/lib.config'\nexport * from './lib/config/utils.config'\n\n/**\n * Guards\n */\nexport * from './lib/guards/auth/auth.guard'\nexport * from './lib/guards/role/role.guard'\n\n/**\n * Pages\n */\nexport * from './lib/pages/auth-callback/auth-callback.page'\nexport * from './lib/pages/auth-error/auth-error.page'\nexport * from './lib/pages/forbidden/forbidden.page'\nexport * from './lib/pages/not-found/not-found.page'\n\n/**\n * Services\n */\nexport * from './lib/services/auth/auth.service'\n\n/**\n * Signals\n */\nexport * from './lib/signals/trpcResource/trpcResource'\nexport * from './lib/signals/fetch-signal/fetch-signal'\nexport * from './lib/signals/debounced/debounced'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i6","i1"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAQa,kBAAkB,CAAA;IAC7B,WAAW,GAAW,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;wGADpC,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,kBAAkB,sECR/B,6WAUA,EAAA,MAAA,EAAA,CAAA,+cAAA,CAAA,EAAA,CAAA;;4FDFa,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAN9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,WACb,EAAE,EAAA,QAAA,EAAA,6WAAA,EAAA,MAAA,EAAA,CAAA,+cAAA,CAAA,EAAA;;;MEFA,WAAW,GAAG,IAAI,cAAc,CAAa,aAAa;;AC2BvE;;;AAGG;MACU,WAAW,CAAA;AACd,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,IAAA,cAAc,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAC9C,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;IAEnB,UAAU,GAAG,SAAS;AACtB,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAE5C;;;AAGG;AACH,IAAA,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;AAE7B,IAAA,WAAA,GAAA;QACE,eAAe,CAAC,MAAK;YACnB,MAAM,CACJ,MAAK;AACH,gBAAA,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE;gBACrC,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC,KAAK,EAAE;AAC5C,oBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,aAAa,CAAY,OAAO,CAAC,IAAI,CAAC,CAAC;;gBAEhE,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC,UAAU,EAAE;AACjD,oBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;;aAEhC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B;AACH,SAAC,CAAC;;AAGJ;;;AAGG;AACH,IAAA,KAAK,GAAG,CAAC,OAAgB,KAAI;QAC3B,IAAI,OAAO,EAAE;YACX,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;;AAElD,QAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AAClB,YAAA,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,gBAAgB;AACvD,SAAA,CAAC;AACJ,KAAC;AAED;;;;;AAKG;IACH,gBAAgB,GAAG,MAAK;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AAAE,YAAA,OAAO,IAAI;AAEtC,QAAA,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC;QACpD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;AAC5C,YAAA,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACvB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;;;AAG1C,QAAA,OAAO,IAAI;AACb,KAAC;AAED;;;;AAIG;IACH,kBAAkB,GAAG,YAA0B;AAC7C,QAAA,IAAI;YACF,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;AAC1D,YAAA,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;AAE1C,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE;gBACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC3B;;AAGF,YAAA,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,oBAAoB,EAAE;gBACrE,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE;AACrD,aAAA,CAAC;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE;AAAE,gBAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC;YACxD,MAAM,WAAW,GACf,GAAG,CAAC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,GAAG,IAAI;AAErD,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE;YAE7C,MAAM,SAAS,GAAG,WAAW,IAAI,UAAU,IAAI,aAAa,IAAI,GAAG;YACnE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;;QACjC,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;AAClB,YAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;;AAE9B,KAAC;AAED;;AAEG;IACH,MAAM,GAAG,CAAC,OAAgB,KACxB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,IAAI,GAAG,CAAC;AACvD,KAAA,CAAC;AAEJ;;AAEG;AACH,IAAA,KAAK,GAAG,QAAQ,CAAqB,MAAK;QACxC,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK;AAC5B,KAAC,CAAC;AAEF;;AAEG;IACH,WAAW,GAAG,QAAQ,CAAqB,MACzC,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,CACpD;AAED;;AAEG;AACH,IAAA,WAAW,GAAG,QAAQ,CAAkC,MAAK;QAC3D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;AAClC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,MAAM,GAAG,QAAQ,CAAqB,MAAK;QACzC,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,OAAO,GAAG,QAAQ,CAAqB,MAAK;QAC1C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,aAAa,GAAG,QAAQ,CAAkC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa;AACpC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,WAAW,GAAG,QAAQ,CAA4B,MAAK;QACrD,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;AAClC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,cAAc,GAAG,QAAQ,CAAqC,MAAK;QACjE,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc;AACrC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAqB,MAAK;QAC/C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,kBAAkB,GAAG,QAAQ,CAAkC,MAAK;QAClE,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,kBAAkB;AACzC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,QAAQ,GAAG,QAAQ,CAAqB,MAAK;QAC3C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ;AAC/B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAmC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,IAAI,GAAG,QAAQ,CAA2B,MAAK;QAC7C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;AAC3B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAmC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;wGArNS,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAX,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAW,cANV,MAAM,EAAA,CAAA;;4FAMP,WAAW,EAAA,UAAA,EAAA,CAAA;kBAPvB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;MCCY,kBAAkB,CAAA;AAC7B,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;IAC1B,MAAM,GAAG,KAAK,EAAgB;AAE9B,IAAA,YAAY,CAAC,IAAgB,EAAA;QAC3B,OAAO,MAAM,IAAI,IAAI;;;IAIvB,gBAAgB,GAAkB,IAAI;;AAGtC,IAAA,cAAc,CAAC,IAAY,EAAA;AACzB,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;;;AAItE,IAAA,MAAM,CAAC,IAAY,EAAA;AACjB,QAAA,OAAO,IAAI,CAAC,gBAAgB,KAAK,IAAI;;wGAlB5B,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC7B/B,0uEAmDA,EAAA,MAAA,EAAA,CAAA,0pEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED1BY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,UAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAIX,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAN9B,SAAS;+BACE,YAAY,EAAA,OAAA,EACb,CAAC,YAAY,CAAC,EAAA,QAAA,EAAA,0uEAAA,EAAA,MAAA,EAAA,CAAA,0pEAAA,CAAA,EAAA;;;AErBzB,SAAS,YAAY,CAA2B,SAAyB,EAAE,KAA0B,EAAE,OAA6C,EAAA;AAClJ,IAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC;AAEpC,IAAA,MAAM,KAAK,GAAG,MAAM,CAA6B,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAClG,IAAA,MAAM,KAAK,GAAG,MAAM,CAAiC,SAAS,CAAC;AAC/D,IAAA,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC;AAExC,IAAA,IAAI,OAAO,EAAE,WAAW,EAAE;AACxB,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,SAAS,KAAI;;AAErC,YAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;YACxC,SAAS,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;;;AAInC,YAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;AAClC,SAAC,EAAE,EAAE,QAAQ,EAAG,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAC,CAAC;;IAGzD,MAAM,OAAO,GAAG,OACd,WAAyB,EACzB,uBAAA,GAAmC,IAAI,KACrC;;AAEF,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AAEpB,QAAA,IAAI;YACF,KAAK,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,YAAY,EAAE,EAAE;AACxC,gBAAA,MAAM,EAAE;AACT,aAAA,CAAC,CAAC;AACH,YAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;;QACpB,OAAO,GAAG,EAAE;AACZ,YAAA,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE;;;;;gBAK1B,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,KAAK,YAAY,IAAI,uBAAuB,EAAE;oBAC/D;;AAEF,gBAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;;iBACT;;gBAEL,OAAO,CAAC,KAAK,CAAC,qDAAqD,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;AAEnF,YAAA,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC;;AAElC,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,KAAC;IAED,OAAO;QACL,KAAK;QACL,KAAK;QACL,SAAS;QACT;KACD;AACH;AAEA,SAAS,iBAAiB,CAA2B,aAAiC,EAAA;IACpF,OAAO;AACL,QAAA,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE;AAC5B,QAAA,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE;AAC5B,QAAA,SAAS,EAAE,aAAa,CAAC,SAAS,EAAE;KACrC;AACH;;ACnEa,MAAA,SAAS,GAAG,CAAI,WAAsB,EAAE,IAAA,GAAe,GAAG,KAAI;AACzE,IAAA,MAAM,eAAe,GAAG,MAAM,CAAI,WAAW,EAAE,CAAC;AAChD,IAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,KAAK,KAAK,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IAEvE,MAAM,CAAC,MAAK;AACV,QAAA,SAAS,CAAC,WAAW,EAAE,CAAC;AAC1B,KAAC,CAAC;AAEF,IAAA,OAAO,eAAe;AACxB;AAEA,MAAM,QAAQ,GAAG,CAAC,QAAkC,EAAE,IAAY,KAAI;AACpE,IAAA,IAAI,SAA6B;AACjC,IAAA,OAAO,CAAC,GAAG,IAAW,KAAI;AACxB,QAAA,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC;AAC9B,QAAA,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,MAAK;AACjC,YAAA,QAAQ,CAAC,GAAG,IAAI,CAAC;SAClB,EAAE,IAAI,CAAC;AACV,KAAC;AACH,CAAC;;ACaY,MAAA,eAAe,GAAG,CAC7B,MAA6B,KAC1B;;MCQQ,kBAAkB,CAAA;AACrB,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAEnC,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAgC;AACvD,IAAA,UAAU,GAAG,KAAK,CAAsB,EAAE,CAAC;IAE3C,UAAU,GAAa,EAAE;IACzB,gBAAgB,GAAa,EAAE;AAC/B,IAAA,SAAS;AACT,IAAA,cAAc,GAAG,KAAK,CAAQ,EAAE,CAAC;AAEjC,IAAA,YAAY;IAEZ,QAAQ,GAAA;AACN,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;QAEzB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE3E,IAAI,GAAG,CAAC,WAAW,EAAE,IAAI,KAAK,QAAQ,EAAE;AACtC,YAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,uBAAuB,CAAC;AACtD,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CACjC,GAAG,CAAC,WAAW,CAAC,KAAK,EACrB,SAAS,EACT,SAAS,EACT,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAC5B;;AAGH,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY,CAC9B,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EACvB,OAAO;AACL,YAAA,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE;AAC9B,YAAA,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE;AAChC,YAAA,IAAI,EAAE;AACJ,gBAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;AACvB,gBAAA,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE;AAChC,aAAA;AACD,YAAA,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ;AACvC,gBAAA,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;AACxB,aAAA;YACD,GAAG,IAAI,CAAC,UAAU,EAAE;AACrB,SAAA,CAAC,EACF;AACE,YAAA,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACxB,SAAA,CACF;;AAGH,IAAA,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AACnB,IAAA,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AACxC,IAAA,OAAO,GAAG,MAAM,CAAyB,EAAE,CAAC;AAC5C,IAAA,gBAAgB,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;AAE1C,IAAA,MAAM,GAAG,YAAY,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;AAChE,IAAA,aAAa,GAAG,YAAY,CAC1B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,IAAI,KAAK,CAC1D;AAED,IAAA,SAAS,GAAG,YAAY,CAAC,MAAK;QAC5B,IAAI,CAAC,MAAM,EAAE;AACb,QAAA,OAAO,CAAC;AACV,KAAC,CAAC;IAEF,cAAc,CAAC,GAAW,EAAE,GAAW,EAAA;QACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;;AAEpD,IAAA,kBAAkB,CAAC,CAAY,EAAA;QAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;;AAEjC,IAAA,YAAY,CAAC,IAAU,EAAA;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;QACnE,IAAI,CAAC,aAAa,CAAC,GAAG,CACpB,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,IAAI,KAAK,CACtE;AACD,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;;IAEvB,iBAAiB,GAAA;AACf,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,EAAE,CAAC;;AAGzD,IAAA,UAAU,CAAC,GAAQ,EAAA;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW;AAC7C,QAAA,IAAI,CAAC,WAAW;YAAE;AAElB,QAAA,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,EAAE;AAChC,YAAA,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC;;AACnB,aAAA,IAAI,WAAW,CAAC,IAAI,KAAK,QAAQ,EAAE;AACxC,YAAA,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC;;QAE7B,IAAI,CAAC,iBAAiB,EAAE;;IAG1B,aAAa,GAAA;QACX,IAAI,CAAC,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,KAAK;QACjC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM;AAClD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;QAC5D,OAAO,WAAW,KAAK,OAAO;;IAGhC,aAAa,GAAA;QACX,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;AACrB,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE;AACxB,YAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;;aACjB;AACL,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;;QAEnE,IAAI,CAAC,iBAAiB,EAAE;;AAG1B,IAAA,aAAa,CAAC,GAAS,EAAA;QACrB,IAAI,CAAC,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,EAAE;QAC9B,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,CAAG,EAAA,IAAI,CAAC,aAAa,EAAE,GAAG,UAAU,GAAG,QAAQ,MAAM;;QAE9D,OAAO,CAAA,EAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAQ,KAAA,EAAA,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAA,CAAE;;wGArHjF,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5C/B,8yIA8IA,EDhHI,MAAA,EAAA,CAAA,6cAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,cAAc,inCACd,wBAAwB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,mCAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACxB,kBAAkB,EAClB,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,WAAA,EAAA,QAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,cAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,MAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,cAAc,6sBACd,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACX,eAAe,EACf,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,aAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,aAAa,idACb,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,CAAA,gBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,kBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,iBAAiB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,GAAA,CAAA,WAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,WAAA,EAAA,IAAA,EAAA,UAAA,EAAA,eAAA,EAAA,MAAA,EAAA,OAAA,EAAA,eAAA,EAAA,UAAA,EAAA,OAAA,EAAA,qBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAKR,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAjB9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,EACb,OAAA,EAAA;wBACP,cAAc;wBACd,wBAAwB;wBACxB,kBAAkB;wBAClB,cAAc;wBACd,WAAW;wBACX,eAAe;wBACf,aAAa;wBACb,aAAa;wBACb,eAAe;wBACf,iBAAiB;AAClB,qBAAA,EAAA,QAAA,EAAA,8yIAAA,EAAA,MAAA,EAAA,CAAA,6cAAA,CAAA,EAAA;;;MErCU,WAAW,GAAG,CAAC,MAAkB,MAAgB;AAC5D,IAAA,OAAO,EAAE,WAAW;AACpB,IAAA,QAAQ,EAAE,MAAM;AACjB,CAAA;;ACFD;;AAEG;MACU,SAAS,GAAkB,CAAC,KAAK,EAAE,KAAK,KAAI;AACvD,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACvC,IAAA,IAAG,CAAC,WAAW,CAAC,aAAa,EAAE,EAAC;AAC9B,QAAA,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5B,QAAA,OAAO,KAAK;;AAEd,IAAA,OAAO,IAAI;AACb;;ACTA;;;;;;;;;;;;;AAaG;MACU,gBAAgB,GAAiD,CAAC,GAAG,YAAY,KAAI;AAChG,IAAA,OAAO,CAAC,MAAM,EAAE,KAAK,KAAI;AACvB,QAAA,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACvC,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAE7B,QAAA,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE;AAChC,YAAA,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5B,YAAA,OAAO,KAAK;;QAGd,MAAM,SAAS,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,KAAK;QAClD,MAAM,OAAO,GACX,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK;AAEjE,QAAA,OAAO,OAAO,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACtE,KAAC;AACH;;MC1Ba,gBAAgB,CAAA;AAC3B,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;AAE1B,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;;wGAJrB,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,gBAAgB,6ECT7B,+DAEM,EAAA,MAAA,EAAA,CAAA,wKAAA,CAAA,EAAA,CAAA;;4FDOO,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAN5B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,WACpB,EAAE,EAAA,QAAA,EAAA,+DAAA,EAAA,MAAA,EAAA,CAAA,wKAAA,CAAA,EAAA;;;MEMA,aAAa,CAAA;wGAAb,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,aAAa,2ECX1B,mTAYA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAC,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,aAAa,EAAA,UAAA,EAAA,CAAA;kBANzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,WAClB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,mTAAA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA;;;MEIvD,aAAa,CAAA;wGAAb,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,aAAa,0ECX1B,+SAYA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,aAAa,EAAA,UAAA,EAAA,CAAA;kBANzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,+SAAA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA;;;MEIvD,YAAY,CAAA;wGAAZ,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,YAAY,0ECXzB,wUAYA,EAAA,MAAA,EAAA,CAAA,8LAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,YAAY,EAAA,UAAA,EAAA,CAAA;kBANxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,wUAAA,EAAA,MAAA,EAAA,CAAA,8LAAA,CAAA,EAAA;;;AEHpE;;;;AAIG;AACH,SAAS,iBAAiB,CACxB,OAAiC,EACjC,MAAkB,EAClB,SAAwC,EACxC,OAAmD,EAAA;;AAGnD,IAAA,MAAM,cAAc,GAAG,QAAQ,CAAqB,OAAO,CAAC;AAE5D,IAAA,MAAM,KAAK,GAAG,MAAM,CAAuB,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5F,IAAA,MAAM,aAAa,GAAG,MAAM,CAA4B,SAAS,CAAC;AAClE,IAAA,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC;AACxC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAqB,SAAS,CAAC;AACxD,IAAA,MAAM,OAAO,GAAG,MAAM,CAAqC,SAAS,CAAC;AAErE,IAAA,MAAM,MAAM,GAAG,MAAM,CAAoB,MAAM,CAAC;AAChD,IAAA,MAAM,KAAK,GAAG,MAAM,CAAoB,SAAS,CAAC;AAElD,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,SAAS,GAA0B,SAAS;AAChD,IAAA,IAAI,OAAO,EAAE,WAAW,EAAE;AACxB,QAAA,SAAS,GAAG,MAAM,CAAC,CAAC,SAAS,KAAI;;AAE/B,YAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;YACxC,SAAS,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;;AAGnC,YAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;SACjC,EAAE,EAAE,QAAQ,EAAG,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAC,CAAC;;IAGjD,MAAM,OAAO,GAAG,OACd,WAAyB,EACzB,uBAAiC,KAC/B;;AAEF,QAAA,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,WAAW;YAAE;;AAGvC,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,QAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5B,QAAA,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,QAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,QAAA,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;AACrB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;;AAGpB,QAAA,MAAM,GAAG,GAAG,cAAc,EAAE;AAC5B,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG;AACnB,QAAA,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM;AACzB,QAAA,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO;AAClC,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI;;QAGrB,IAAI,GAAG,GAAG,GAAG;QACb,IAAI,MAAM,EAAE;AACV,YAAA,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE;AAC1C,YAAA,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE;AACxB,gBAAA,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;AAC3B,oBAAA,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;YAEjD,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE;;;QAIlE,MAAM,eAAe,GAAG;cACtB,MAAM,CAAC,WAAW,CAClB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CACnC,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,SAAS,CACb;cAEvB,SAAS;AAEX,QAAA,IAAI;;AAEF,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM;AACN,gBAAA,OAAO,EAAE,eAAe;;AAExB,gBAAA,IAAI,EAAE,IAAI;AACV,gBAAA,MAAM,EAAE,WAAW;AACpB,aAAA,CAAC;;AAGF,YAAA,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;;YAG/B,MAAM,UAAU,GAA2B,EAAE;YAC7C,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,KAAI;AACpC,gBAAA,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG;AACvB,aAAC,CAAC;AACF,YAAA,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;;AAGvB,YAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;gBACf,KAAK,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;AACpC,gBAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;;iBACjB;;AAEL,gBAAA,IAAI;oBACF,aAAa,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACxC,oBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,oBAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;;AACtB,gBAAA,MAAM;AACN,oBAAA,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC;;;;QAGtD,OAAO,GAAQ,EAAE;AACjB,YAAA,IAAI,GAAG,YAAY,KAAK,EAAE;;;;;gBAKxB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,uBAAuB,EAAE;oBACxD;;AAEF,gBAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;;iBACT;;AAEL,gBAAA,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;AAEnC,YAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,YAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;;AAErB,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,KAAC;IAED,MAAM,OAAO,GAAG,MAAK;;QAEnB,IAAI,MAAM,EAAE,KAAK,WAAW;YAAE;QAE9B,IAAI,SAAS,EAAE;YACb,SAAS,CAAC,OAAO,EAAE;;AAErB,QAAA,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AACvB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,QAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5B,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,QAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,KAAC;IAED,OAAO;QACL,KAAK;QACL,aAAa;QACb,SAAS;QACT,UAAU;QACV,OAAO;QACP,MAAM;QACN,KAAK;QACL,OAAO;QACP;KACD;AACH;AAEA;AACA;AACA;AACA,MAAM,YAAY,GAAG,CAAkB,MAAkB,EAAE,SAAwC,KACjG,CAAC,OAAiC,EAAE,OAA2C,KAC7E,iBAAiB,CAAuB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;AAEhF;AACA,MAAM,eAAe,GAA6B,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AACzF,MAAM,eAAe,GAAgC,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AAC5F,MAAM,eAAe,GAA8B,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AAC1F,MAAM,sBAAsB,GAAqC,CAAC,QAAkB,KAAK,QAAQ,CAAC,WAAW,EAAE;AAE/G;AACA;AACA;AACM,MAAA,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAErE;AACA;AACA;AACA,WAAW,CAAC,GAAG,GAAG,YAAY,CAC5B,KAAK,EACL,eAAe,CACa;AAC9B,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAEzE;AACA;AACA;AACA,WAAW,CAAC,IAAI,GAAG,YAAY,CAC7B,MAAM,EACN,eAAe,CACc;AAC/B,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,WAAW,GAAG,YAAY,CAAC,MAAM,EAAE,sBAAsB,CAAC;AAE3E;AACA;AACA;AACA,WAAW,CAAC,GAAG,GAAG,YAAY,CAC5B,KAAK,EACL,eAAe,CACa;AAC9B,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAEzE;AACA;AACA;AACA,WAAW,CAAC,KAAK,GAAG,YAAY,CAC9B,OAAO,EACP,eAAe,CACe;AAChC,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,sBAAsB,CAAC;AAE7E;AACA;AACA;AACA,WAAW,CAAC,MAAM,GAAG,YAAY,CAC/B,QAAQ,EACR,eAAe,CACgB;AACjC,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,WAAW,GAAG,YAAY,CAAC,QAAQ,EAAE,sBAAsB,CAAC;;ACrP/E;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"fhss-web-team-frontend-utils.mjs","sources":["../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.ts","../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.html","../../../projects/frontend-utils/src/lib/config/lib.config.ts","../../../projects/frontend-utils/src/lib/services/auth/auth.service.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.html","../../../projects/frontend-utils/src/lib/signals/trpcResource/trpcResource.ts","../../../projects/frontend-utils/src/lib/signals/debounced/debounced.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.types.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.html","../../../projects/frontend-utils/src/lib/config/utils.config.ts","../../../projects/frontend-utils/src/lib/guards/auth/auth.guard.ts","../../../projects/frontend-utils/src/lib/guards/role/role.guard.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.html","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.html","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.ts","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.html","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.ts","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.html","../../../projects/frontend-utils/src/lib/signals/fetch-signal/fetch-signal.ts","../../../projects/frontend-utils/src/public-api.ts","../../../projects/frontend-utils/src/fhss-web-team-frontend-utils.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'byu-footer',\n imports: [],\n templateUrl: './byu-footer.component.html',\n styleUrl: './byu-footer.component.scss'\n})\nexport class ByuFooterComponent {\n currentYear: number = new Date().getFullYear(); // Automatically updates the year\n}\n","<footer>\n <p class=\"title\"><a href=\"https://www.byu.edu/\">BRIGHAM YOUNG UNIVERSITY</a></p>\n <p>Provo, UT 84602, USA | © {{ currentYear }} All rights reserved.</p>\n <p>\n <a href=\"https://privacy.byu.edu/privacy-notice\">Privacy Notice</a> |\n <a href=\"https://privacy.byu.edu/cookie-prefs\">Cookie Preferences</a>\n </p>\n</footer>\n \n\n","import { InjectionToken } from '@angular/core';\n\nexport const FHSS_CONFIG = new InjectionToken<FhssConfig>('FHSS_CONFIG');\n\nexport interface FhssConfig {\n roleHomePages: Record<string, string>;\n}\n","import {\n Injectable,\n inject,\n computed,\n afterNextRender,\n effect,\n Injector,\n signal,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport {\n KEYCLOAK_EVENT_SIGNAL,\n KeycloakEventType,\n ReadyArgs,\n typeEventArgs,\n} from 'keycloak-angular';\nimport Keycloak, {\n KeycloakFlow,\n KeycloakResourceAccess,\n KeycloakResponseMode,\n KeycloakResponseType,\n KeycloakRoles,\n KeycloakTokenParsed,\n} from 'keycloak-js';\nimport { FHSS_CONFIG } from '../../config/lib.config';\n\n@Injectable({\n providedIn: 'root',\n})\n/**\n * AuthService provides a wrapper around the Keycloak JavaScript adapter, exposing its properties and methods\n * as Angular signals for reactive programming. It simplifies authentication, token management, and role-based access control.\n */\nexport class AuthService {\n private keycloak = inject(Keycloak);\n private keycloakSignal = inject(KEYCLOAK_EVENT_SIGNAL);\n private router = inject(Router);\n private config = inject(FHSS_CONFIG);\n\n private readonly nextUriKey = 'nextUri';\n private readonly injector = inject(Injector);\n\n /**\n * Signal indicating whether the user is authenticated.\n * Returns `true` if authenticated, `false` otherwise.\n */\n authenticated = signal(false);\n\n constructor() {\n afterNextRender(() => {\n effect(\n () => {\n const kcEvent = this.keycloakSignal();\n if (kcEvent.type === KeycloakEventType.Ready) {\n this.authenticated.set(typeEventArgs<ReadyArgs>(kcEvent.args));\n }\n if (kcEvent.type === KeycloakEventType.AuthLogout) {\n this.authenticated.set(false);\n }\n },\n { injector: this.injector },\n );\n });\n }\n\n /**\n * Initiates the login process. Optionally stores a route to redirect to after login.\n * @param nextUri - The route to navigate to after successful login.\n */\n login = (nextUri?: string) => {\n if (nextUri) {\n sessionStorage.setItem(this.nextUriKey, nextUri);\n }\n this.keycloak.login({\n redirectUri: window.location.origin + '/auth-callback',\n });\n };\n\n /**\n * Gets the user's role home route\n *\n * @returns the user's role's home route,\n * or null if there isn't one\n */\n getRoleHomeRoute = () => {\n if (!this.authenticated()) return null;\n\n const userRoles = new Set(this.realmAccess()?.roles);\n for (const role in this.config.roleHomePages) {\n if (userRoles.has(role)) {\n return this.config.roleHomePages[role];\n }\n }\n return null;\n };\n\n /**\n * Handles user provisioning.\n *\n * @returns the uri to which the application should navigate\n */\n handleAuthCallback = async (): Promise<void> => {\n try {\n const savedRoute = sessionStorage.getItem(this.nextUriKey);\n sessionStorage.removeItem(this.nextUriKey);\n\n if (!this.authenticated()) {\n this.router.navigate(['/']);\n return;\n }\n\n const res = await fetch(window.location.origin + '/api/auth/callback', {\n headers: { Authorization: this.bearerToken() ?? '' },\n });\n\n if (!res.ok) throw new Error('User provisioning failed');\n const customRoute: string | null =\n res.status === 200 ? (await res.json()).next : null;\n\n const userHomeRoute = this.getRoleHomeRoute();\n\n const nextRoute = customRoute ?? savedRoute ?? userHomeRoute ?? '/';\n this.router.navigate([nextRoute]);\n } catch (err) {\n console.error(err);\n this.logout('/auth-error');\n }\n };\n\n /**\n * Logs the user out of the application.\n */\n logout = (nextUri?: string) =>\n this.keycloak.logout({\n redirectUri: window.location.origin + (nextUri ?? '/'),\n });\n\n /**\n * Signal for the base64-encoded token used in the `Authorization` header.\n */\n token = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.token;\n });\n\n /**\n * Signal for the Bearer token, prefixed with \"Bearer \".\n */\n bearerToken = computed<string | undefined>(() =>\n this.token() ? 'Bearer ' + this.token() : undefined,\n );\n\n /**\n * Signal for the parsed token as a JavaScript object.\n */\n tokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.tokenParsed;\n });\n\n /**\n * Signal for the user ID (Keycloak subject).\n */\n userId = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.subject;\n });\n\n /**\n * Signal for the base64-encoded ID token.\n */\n idToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idToken;\n });\n\n /**\n * Signal for the parsed ID token as a JavaScript object.\n */\n idTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idTokenParsed;\n });\n\n /**\n * Signal for the realm roles associated with the token.\n */\n realmAccess = computed<KeycloakRoles | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.realmAccess;\n });\n\n /**\n * Signal for the resource roles associated with the token.\n */\n resourceAccess = computed<KeycloakResourceAccess | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.resourceAccess;\n });\n\n /**\n * Signal for the base64-encoded refresh token.\n */\n refreshToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshToken;\n });\n\n /**\n * Signal for the parsed refresh token as a JavaScript object.\n */\n refreshTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshTokenParsed;\n });\n\n /**\n * Signal for the estimated time difference between the browser and Keycloak server in seconds.\n */\n timeSkew = computed<number | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.timeSkew;\n });\n\n /**\n * Signal for the response mode passed during initialization.\n */\n responseMode = computed<KeycloakResponseMode | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseMode;\n });\n\n /**\n * Signal for the flow type used during initialization.\n */\n flow = computed<KeycloakFlow | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.flow;\n });\n\n /**\n * Signal for the response type sent to Keycloak during login requests.\n */\n responseType = computed<KeycloakResponseType | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseType;\n });\n}\n","import { Component, input, inject } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\ntype HeaderLink = {\n text: string;\n path: string;\n};\n\n// A HeaderMenu can be either a simple link with path,\n// OR a menu group with nested items\ntype HeaderMenu = HeaderLink | {\n text: string;\n items: HeaderLink[];\n}\n\nexport type HeaderConfig = {\n title: HeaderLink;\n subtitle?: HeaderLink;\n breadcrumbs?: HeaderLink[];\n menu?: HeaderMenu[];\n}\n\n@Component({\n selector: 'byu-header',\n imports: [RouterModule],\n templateUrl: './byu-header.component.html',\n styleUrl: './byu-header.component.scss'\n})\nexport class ByuHeaderComponent {\n auth = inject(AuthService)\n config = input<HeaderConfig>();\n\n isHeaderLink(item: HeaderMenu): item is HeaderLink {\n return 'path' in item;\n }\n\n // Track which dropdown is open (null means none are open)\n openDropdownText: string | null = null;\n \n // Toggle function — if clicking the same dropdown, close it; otherwise open it\n toggleDropdown(text: string) {\n this.openDropdownText = this.openDropdownText === text ? null : text;\n }\n \n // Check if a given dropdown is currently open\n isOpen(text: string): boolean {\n return this.openDropdownText === text;\n }\n}\n","<header>\n <div class=\"top\" >\n <img class=\"logo\" src=\"/BYU_monogram_white@2x.png\" alt=\"BYU\">\n <div class=\"titles\"> \n <div class=\"breadcrumbs\">\n @for (breadcrumb of config()?.breadcrumbs; track breadcrumb.text){\n <a [href]=\"breadcrumb.path\" >{{ breadcrumb.text }}</a>\n }\n </div>\n <a [routerLink]=\"config()?.title?.path\" class=\"title\">{{ config()?.title?.text }}</a>\n <a [routerLink]=\"config()?.subtitle?.path\" class=\"subtitle\">{{ config()?.subtitle?.text }}</a>\n </div>\n <div class=\"signin\">\n <p>{{ this.auth.tokenParsed()?.['given_name'] ?? '' }}</p>\n <svg class=\"signin-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n <path fill=\"currentcolor\" d=\"M50 95c-26 0-34-18-34-18 3-12 8-18 17-18 5 5 10 7 17 7s12-2 17-7c9 0 14 6 17 18 0 0-7 18-34 18z\"></path>\n <circle cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"currentcolor\" stroke-width=\"10\"></circle>\n <circle fill=\"currentcolor\" cx=\"50\" cy=\"40\" r=\"20\"></circle>\n </svg>\n @if (auth.authenticated()) {\n <a class=\"signin-link\" (click)=\"auth.logout()\">Sign Out</a>\n } @else {\n <a class=\"signin-link\" (click)=\"auth.login()\">Sign In</a>\n }\n </div>\n </div>\n <div class=\"bottom\">\n <nav>\n @for (menuItem of config()?.menu; track menuItem.text){\n @if (isHeaderLink(menuItem)) {\n <li class = \"nav-item\">\n <a class=\"nav-item-content\" [routerLink]=\"menuItem.path\">{{ menuItem.text }}</a>\n </li>\n } @else {\n <li class=\"nav-item dropdown\" (click)=\"toggleDropdown(menuItem.text)\">\n <div class=\"nav-item-content\" >{{ menuItem.text }}</div>\n @if (openDropdownText === menuItem.text) {\n <ul class = \"dropdown-item-menu\"> \n @for(dropItem of menuItem.items; track dropItem.text){\n <li class = \"dropdown-item\">\n <a class=\"dropdown-item-content\" [routerLink]=\"dropItem.path\">{{ dropItem.text }}</a>\n </li>\n }\n </ul>\n }\n </li>\n }\n }\n </nav>\n </div>\n</header>\n","import { computed, effect, EffectRef, inject, Injector, signal } from \"@angular/core\";\nimport { isTRPCClientError, Resolver } from \"@trpc/client\";\nimport { ResolverDef, TrpcResource ,TrpcResourceOptions } from \"./trpcResource.types\";\n\nfunction trpcResource<TDef extends ResolverDef>(procedure: Resolver<TDef>, input: () => TDef['input'], options?: TrpcResourceOptions<TDef['output']>): TrpcResource<TDef> {\n const currentInput = computed(input);\n\n const value = signal<TDef['output'] | undefined>(options?.defaultValue, { equal: options?.equal });\n const error = signal<TDef['errorShape'] | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n\n if (options?.autoRefresh) {\n const effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n // refresh reads currentInput which triggers the effect\n refresh(controller.signal, true);\n }, { injector: options?.injector || inject(Injector)});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort: boolean = true,\n ) => {\n // Reset signals for a fresh request.\n isLoading.set(true);\n error.set(undefined);\n\n try {\n value.set(await procedure(currentInput(), {\n signal: abortSignal\n }));\n error.set(undefined)\n } catch (err) {\n if (isTRPCClientError(err)) {\n // if the trpc request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.cause?.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n console.error(\"A non-tRPC error has occured on this trpcResource: \", String(err));\n }\n value.set(options?.defaultValue);\n }\n isLoading.set(false);\n }\n\n return {\n value,\n error,\n isLoading,\n refresh\n };\n}\n\nfunction debugTrpcResource<TDef extends ResolverDef>(_trpcResource: TrpcResource<TDef>) {\n return {\n value: _trpcResource.value(),\n error: _trpcResource.error(),\n isLoading: _trpcResource.isLoading(),\n }\n}\n\nexport { debugTrpcResource, trpcResource };","import { effect, signal, Signal } from \"@angular/core\";\n\nexport const debounced = <T>(inputSignal: Signal<T>, wait: number = 400) => {\n const debouncedSignal = signal<T>(inputSignal());\n const setSignal = debounce((value) => debouncedSignal.set(value), wait);\n\n effect(() => {\n setSignal(inputSignal())\n })\n\n return debouncedSignal;\n}\n\nconst debounce = (callback: (...args: any[]) => void, wait: number) => {\n let timeoutId: number | undefined;\n return (...args: any[]) => {\n window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n}","import { Resolver } from '@trpc/client';\nimport { ResolverDef } from '../../signals/trpcResource/trpcResource.types';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\n\nexport type FhssTableConfig<TDef extends ResolverDef> = {\n procedure: Resolver<TDef>;\n columns: {\n [K in keyof TDef['output']['data'][number]]: {\n hide?: boolean;\n header?: string;\n allowSort?: boolean;\n individualFilter?: boolean;\n };\n };\n showSearch?: boolean;\n sorting: {\n defaultSortBy: Extract<keyof TDef['output']['data'][number], string>;\n defaultSortDirection?: 'asc' | 'desc';\n };\n pagination: {\n pageSize: number;\n hideControls?: boolean;\n };\n interaction?:\n | {\n type: 'click';\n onClick: (obj: TDef['output']['data'][number]) => void;\n }\n | {\n type: 'select';\n multi?: boolean;\n };\n};\n\nexport const makeTableConfig = <TDef extends ResolverDef>(\n config: FhssTableConfig<TDef>,\n) => config;\n\nexport type AnyResolver = {\n input: any;\n output: { totalCount: number; data: any[] };\n transformer: any;\n errorShape: {\n code: any;\n message: string;\n data: any;\n };\n};\n\nexport type AnyResource = ReturnType<typeof trpcResource<AnyResolver>>;\n","import {\n Component,\n inject,\n Injector,\n input,\n linkedSignal,\n model,\n OnInit,\n signal,\n} from '@angular/core';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\nimport { debounced } from '../../signals/debounced/debounced';\nimport { FhssTableConfig, AnyResolver, AnyResource } from './fhss-table.types';\nexport { makeTableConfig } from './fhss-table.types';\n\nimport { MatTableModule } from '@angular/material/table';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\nimport { MatInputModule } from '@angular/material/input';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatRippleModule } from '@angular/material/core';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { SelectionModel } from '@angular/cdk/collections';\n\n@Component({\n selector: 'fhss-table',\n imports: [\n MatTableModule,\n MatProgressSpinnerModule,\n MatPaginatorModule,\n MatInputModule,\n FormsModule,\n MatButtonModule,\n MatSortModule,\n MatIconModule,\n MatRippleModule,\n MatCheckboxModule,\n ],\n templateUrl: './fhss-table.component.html',\n styleUrl: './fhss-table.component.scss',\n})\nexport class FhssTableComponent implements OnInit {\n private injector = inject(Injector);\n\n config = input.required<FhssTableConfig<AnyResolver>>();\n miscParams = input<Record<string, any>>({});\n\n columnKeys: string[] = [];\n columnsToDisplay: string[] = [];\n selection: SelectionModel<any> | undefined;\n selectedValues = model<any[]>([]);\n\n dataResource!: AnyResource;\n\n ngOnInit() {\n const cfg = this.config();\n\n this.columnKeys = Object.keys(cfg.columns);\n this.columnsToDisplay = this.columnKeys.filter((k) => !cfg.columns[k].hide);\n\n if (cfg.interaction?.type === 'select') {\n this.columnsToDisplay.unshift('table-checkbox-column');\n this.selection = new SelectionModel<any>(\n cfg.interaction.multi,\n undefined,\n undefined,\n (o1, o2) => o1.id === o2.id,\n );\n }\n\n this.dataResource = trpcResource(\n this.config().procedure,\n () => ({\n search: this.debouncedSearch(),\n filters: this.debouncedFilters(),\n sort: {\n property: this.sortBy(),\n direction: this.sortDirection(),\n },\n page: {\n size: this.config().pagination.pageSize,\n index: this.pageIndex(),\n },\n ...this.miscParams(),\n }),\n {\n autoRefresh: true,\n injector: this.injector,\n },\n );\n }\n\n search = signal('');\n debouncedSearch = debounced(this.search);\n filters = signal<Record<string, string>>({});\n debouncedFilters = debounced(this.filters);\n\n sortBy = linkedSignal(() => this.config().sorting.defaultSortBy);\n sortDirection = linkedSignal<'asc' | 'desc'>(\n () => this.config().sorting.defaultSortDirection ?? 'asc',\n );\n\n pageIndex = linkedSignal(() => {\n this.search();\n return 0;\n });\n\n onFilterChange(col: string, val: string) {\n this.filters.update((f) => ({ ...f, [col]: val }));\n }\n onPaginationChange(e: PageEvent) {\n this.pageIndex.set(e.pageIndex);\n }\n onSortChange(sort: Sort) {\n this.sortBy.set(sort.active || this.config().sorting.defaultSortBy);\n this.sortDirection.set(\n sort.direction || this.config().sorting.defaultSortDirection || 'asc',\n );\n this.pageIndex.set(0);\n }\n onSelectionChange() {\n this.selectedValues.set(this.selection?.selected ?? []);\n }\n\n onRowClick(row: any) {\n const interaction = this.config().interaction;\n if (!interaction) return;\n\n if (interaction.type === 'click') {\n interaction.onClick(row);\n } else if (interaction.type === 'select') {\n this.selection?.toggle(row);\n }\n this.onSelectionChange();\n }\n\n isAllSelected() {\n if (!this.selection) return false;\n const numSelected = this.selection.selected.length;\n const numRows = this.dataResource.value()?.data?.length ?? 0;\n return numSelected === numRows;\n }\n\n toggleAllRows() {\n if (!this.selection) return;\n if (this.isAllSelected()) {\n this.selection.clear();\n } else {\n this.selection.select(...(this.dataResource.value()?.data ?? []));\n }\n this.onSelectionChange();\n }\n\n checkboxLabel(row?: any): string {\n if (!this.selection) return '';\n if (!row) {\n return `${this.isAllSelected() ? 'deselect' : 'select'} all`;\n }\n return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;\n }\n}\n","<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\" subscriptSizing=\"dynamic\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" >\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n","import { Provider } from \"@angular/core\";\nimport { FHSS_CONFIG, FhssConfig } from \"./lib.config\";\n\nexport const provideFhss = (config: FhssConfig): Provider => ({\n provide: FHSS_CONFIG,\n useValue: config,\n});\n","import { inject } from '@angular/core';\nimport { CanActivateFn } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\n/**\n * This guard checks if the client is authenticated, redirecting to login if not.\n */\nexport const authGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n if(!authService.authenticated()){\n authService.login(state.url);\n return false;\n }\n return true;\n};\n","import { CanActivateFn, RedirectCommand, Router } from '@angular/router';\nimport { FHSS_CONFIG } from '../../config/lib.config';\nimport { AuthService } from '../../services/auth/auth.service';\nimport { inject } from '@angular/core';\n\n/**\n * Generates a guard function to determine if a user has the required roles to access a route.\n *\n * @example\n * ```typescript\n * const routes: Routes = [\n * {\n * path: 'admin',\n * component: AdminPage,\n * canActivate: [roleGuardFactory(Roles.admin)],\n * },\n * ];\n * ```\n */\nexport const roleGuardFactory: (...allowedRoles: string[]) => CanActivateFn = (...allowedRoles) => {\n return (_route, state) => {\n const authService = inject(AuthService);\n const router = inject(Router);\n\n if (!authService.authenticated()) {\n authService.login(state.url);\n return false;\n }\n\n const userRoles = authService.realmAccess()?.roles;\n const hasRole =\n userRoles?.some((role) => allowedRoles.includes(role)) ?? false;\n\n return hasRole || new RedirectCommand(router.parseUrl('/forbidden'));\n };\n};\n","import { Component, inject } from '@angular/core';\nimport { AuthService } from '../../services/auth/auth.service';\n\n@Component({\n selector: 'app-auth-callback',\n imports: [],\n templateUrl: './auth-callback.page.html',\n styleUrl: './auth-callback.page.scss',\n})\nexport class AuthCallbackPage {\n auth = inject(AuthService)\n\n constructor() {\n this.auth.handleAuthCallback();\n }\n}\n","<div class=\"container\">\n <p>Logging you in...</p>\n</div>","import { Component } from '@angular/core';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\nimport { MatButtonModule } from '@angular/material/button';\n\n@Component({\n selector: 'fhss-auth-error',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './auth-error.page.html',\n styleUrl: './auth-error.page.scss'\n})\nexport class AuthErrorPage {\n\n}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/sad-duck.jpg\" alt=\"sad duck\" />\n <h1>Login Failed</h1>\n <p>Something went wrong while trying to log you in.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-forbidden',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './forbidden.page.html',\n styleUrl: './forbidden.page.scss',\n})\nexport class ForbiddenPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/police-duck.jpg\" alt=\"\" />\n <h1>403 - Forbidden</h1>\n <p>You don't have permission to access this page.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-not-found',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './not-found.page.html',\n styleUrl: './not-found.page.scss',\n})\nexport class NotFoundPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/confused-duck.png\" alt=\"\" />\n <h1>404 - Page not found</h1>\n <p>The page you are looking for doesn't exist or it may have moved.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { computed, effect, EffectRef, inject, Injector, signal, untracked } from '@angular/core';\nimport { FetchSignal, FetchSignalFactory, FetchSignalOptions, FetchSignalRequest, FetchSignalStatus, HttpMethod, Json, ResponseTransformer } from './fetch-signal.types';\n\n\n/**\n * Creates a reactive fetch signal.\n *\n * The request function can include Signals for properties. These are unwrapped in the refresh function.\n */\nfunction createFetchSignal<Response, ErrorResponse, RawResponse>(\n request: () => FetchSignalRequest,\n method: HttpMethod,\n transform: ResponseTransformer<Response>,\n options?: FetchSignalOptions<Response, RawResponse>,\n): FetchSignal<Response, ErrorResponse> {\n // Use a computed signal so that any changes to Signals in the request object trigger updates.\n const currentRequest = computed<FetchSignalRequest>(request);\n\n const value = signal<Response | undefined>(options?.defaultValue, { equal: options?.equal });\n const errorResponse = signal<ErrorResponse | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n const statusCode = signal<number | undefined>(undefined);\n const headers = signal<Record<string, string> | undefined>(undefined);\n\n const status = signal<FetchSignalStatus>('idle');\n const error = signal<Error | undefined>(undefined);\n\n const injector = inject(Injector);\n let effectRef: EffectRef | undefined = undefined;\n if (options?.autoRefresh) {\n effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n refresh(controller.signal, true);\n }, { injector: options?.injector || injector});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort?: boolean,\n ) => {\n // if the fetchSignal has been destroyed, do nothing\n if (untracked(status) === 'destroyed') return;\n\n // Reset signals for a fresh request.\n isLoading.set(true);\n errorResponse.set(undefined);\n statusCode.set(undefined);\n headers.set(undefined);\n status.set('loading');\n error.set(undefined);\n\n // Unwrap the current request.\n const req = currentRequest();\n const url = req.url;\n const params = req.params;\n const requestHeaders = req.headers;\n const body = req.body;\n\n // Build URL with query parameters.\n let uri = url;\n if (params) {\n const searchParams = new URLSearchParams();\n for (const key in params) {\n if (params[key] !== undefined)\n searchParams.append(key, String(params[key]));\n }\n uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();\n }\n \n // Filter out undefined header values\n const filteredHeaders = requestHeaders\n ? Object.fromEntries(\n Object.entries(requestHeaders).filter(\n ([, value]) => value !== undefined\n ) as [string, string][]\n )\n : undefined;\n \n try {\n // send the request\n const response = await fetch(uri, {\n method,\n headers: filteredHeaders,\n // Only include a body if one is provided.\n body: body,\n signal: abortSignal,\n });\n\n // set the status code\n statusCode.set(response.status);\n\n // Extract response headers.\n const headersObj: Record<string, string> = {};\n response.headers.forEach((val, key) => {\n headersObj[key] = val;\n });\n headers.set(headersObj);\n\n // if the response is ok, transform the body\n if (response.ok) {\n value.set(await transform(response));\n status.set('resolved');\n } else {\n // try to parse the error as json\n try {\n errorResponse.set(await response.json());\n value.set(undefined);\n status.set('resolved');\n } catch {\n throw new Error('Unable to parse error response.')\n }\n }\n } catch (err: any) {\n if (err instanceof Error) {\n // if the fetch request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n error.set(new Error(String(err)));\n }\n value.set(undefined);\n status.set('error');\n }\n isLoading.set(false);\n };\n\n const destroy = () => {\n // if the fetchSignal has been destroyed, do nothing\n if (status() === 'destroyed') return;\n\n if (effectRef) {\n effectRef.destroy();\n }\n status.set('destroyed');\n value.set(undefined);\n errorResponse.set(undefined);\n isLoading.set(false);\n statusCode.set(undefined);\n headers.set(undefined);\n error.set(undefined);\n }\n\n return {\n value,\n errorResponse,\n isLoading,\n statusCode,\n headers,\n status,\n error,\n refresh,\n destroy\n };\n}\n\n//\n// Helpers for attaching response transforms.\n//\nconst createHelper = <Response, Error>(method: HttpMethod, transform: ResponseTransformer<Response>) =>\n (request: () => FetchSignalRequest, options?: FetchSignalOptions<Response, any>): FetchSignal<Response, Error> =>\n createFetchSignal<Response, Error, any>(request, method, transform, options);\n\n// Transforms\nconst jsonTransformer: ResponseTransformer<any> = (response: Response) => response.json();\nconst textTransformer: ResponseTransformer<string> = (response: Response) => response.text();\nconst blobTransformer: ResponseTransformer<Blob> = (response: Response) => response.blob();\nconst arrayBufferTransformer: ResponseTransformer<ArrayBuffer> = (response: Response) => response.arrayBuffer();\n\n//\n// Build the defaults - GET chain\n//\nconst fetchSignal = createHelper('GET', jsonTransformer) as FetchSignalFactory;\nfetchSignal.json = createHelper('GET', jsonTransformer);\nfetchSignal.text = createHelper('GET', textTransformer);\nfetchSignal.blob = createHelper('GET', blobTransformer);\nfetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the GET chain\n//\nfetchSignal.get = createHelper(\n 'GET',\n jsonTransformer,\n) as FetchSignalFactory['get'];\nfetchSignal.get.json = createHelper('GET', jsonTransformer);\nfetchSignal.get.text = createHelper('GET', textTransformer);\nfetchSignal.get.blob = createHelper('GET', blobTransformer);\nfetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the POST chain.\n//\nfetchSignal.post = createHelper(\n 'POST',\n jsonTransformer,\n) as FetchSignalFactory['post'];\nfetchSignal.post.json = createHelper('POST', jsonTransformer);\nfetchSignal.post.text = createHelper('POST', textTransformer);\nfetchSignal.post.blob = createHelper('POST', blobTransformer);\nfetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);\n\n//\n// Build the PUT chain.\n//\nfetchSignal.put = createHelper(\n 'PUT',\n jsonTransformer,\n) as FetchSignalFactory['put'];\nfetchSignal.put.json = createHelper('PUT', jsonTransformer);\nfetchSignal.put.text = createHelper('PUT', textTransformer);\nfetchSignal.put.blob = createHelper('PUT', blobTransformer);\nfetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);\n\n//\n// Build the PATCH chain.\n//\nfetchSignal.patch = createHelper(\n 'PATCH',\n jsonTransformer,\n) as FetchSignalFactory['patch'];\nfetchSignal.patch.json = createHelper('PATCH', jsonTransformer);\nfetchSignal.patch.text = createHelper('PATCH', textTransformer);\nfetchSignal.patch.blob = createHelper('PATCH', blobTransformer);\nfetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);\n\n//\n// Build the DELETE chain\n//\nfetchSignal.delete = createHelper(\n 'DELETE',\n jsonTransformer,\n) as FetchSignalFactory['delete'];\nfetchSignal.delete.json = createHelper('DELETE', jsonTransformer);\nfetchSignal.delete.text = createHelper('DELETE', textTransformer);\nfetchSignal.delete.blob = createHelper('DELETE', blobTransformer);\nfetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);\n\nexport { fetchSignal };\nexport type { Json };\n\n","/**\n * Components\n */\nexport * from './lib/components/byu-footer/byu-footer.component'\nexport * from './lib/components/byu-header/byu-header.component'\nexport * from './lib/components/fhss-table/fhss-table.component'\n\n/**\n * Config\n */\nexport * from './lib/config/lib.config'\nexport * from './lib/config/utils.config'\n\n/**\n * Guards\n */\nexport * from './lib/guards/auth/auth.guard'\nexport * from './lib/guards/role/role.guard'\n\n/**\n * Pages\n */\nexport * from './lib/pages/auth-callback/auth-callback.page'\nexport * from './lib/pages/auth-error/auth-error.page'\nexport * from './lib/pages/forbidden/forbidden.page'\nexport * from './lib/pages/not-found/not-found.page'\n\n/**\n * Services\n */\nexport * from './lib/services/auth/auth.service'\n\n/**\n * Signals\n */\nexport * from './lib/signals/trpcResource/trpcResource'\nexport * from './lib/signals/fetch-signal/fetch-signal'\nexport * from './lib/signals/debounced/debounced'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i6","i1"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fhss-web-team/frontend-utils",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^19.2.0",
6
6
  "@angular/core": "^19.2.0"