-
Notifications
You must be signed in to change notification settings - Fork 50
Update Events Dashboard to Angular 14 #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
c231034
Update Events Page
RyCarpenter f99d987
fix unit test
RyCarpenter 9d0bd17
Fix comments from John
RyCarpenter 3ac7788
Make Em The Same
RyCarpenter bd3f17a
Add Icon Fix Test
RyCarpenter d2c6eb5
Final Fixes
RyCarpenter 84ddd81
Description Changes Unit Tests
RyCarpenter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
web-app/admin/src/app/admin/admin-event/admin-events.module.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { NgModule } from '@angular/core'; | ||
| import { CommonModule } from '@angular/common'; | ||
| import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | ||
| import { MatTableModule } from '@angular/material/table'; | ||
| import { MatPaginatorModule } from '@angular/material/paginator'; | ||
| import { MatSortModule } from '@angular/material/sort'; | ||
| import { MatDialogModule } from '@angular/material/dialog'; | ||
| import { MatFormFieldModule } from '@angular/material/form-field'; | ||
| import { MatInputModule } from '@angular/material/input'; | ||
| import { MatButtonModule } from '@angular/material/button'; | ||
| import { MatCheckboxModule } from '@angular/material/checkbox'; | ||
| import { MatIconModule } from '@angular/material/icon'; | ||
| import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; | ||
|
|
||
| import { CoreModule } from '../../core/core.module'; | ||
| import { AdminBreadcrumbModule } from '../admin-breadcrumb/admin-breadcrumb.module'; | ||
| import { EventDashboardComponent } from './dashboard/event-dashboard.component'; | ||
| import { MatSelectModule } from '@angular/material/select'; | ||
| import { MatOptionModule } from '@angular/material/core'; | ||
| import { EventService } from 'src/app/event/event.service'; | ||
| import { CreateEventDialogComponent } from './create-event/create-event.component'; | ||
| import { MatTooltipModule } from '@angular/material/tooltip'; | ||
|
|
||
| @NgModule({ | ||
| declarations: [ | ||
| EventDashboardComponent, | ||
| CreateEventDialogComponent | ||
| ], | ||
| imports: [ | ||
| CommonModule, | ||
| FormsModule, | ||
| CoreModule, | ||
| ReactiveFormsModule, | ||
| MatTableModule, | ||
| MatPaginatorModule, | ||
| MatSortModule, | ||
| MatDialogModule, | ||
| MatFormFieldModule, | ||
| MatInputModule, | ||
| MatButtonModule, | ||
| MatCheckboxModule, | ||
| MatIconModule, | ||
| MatProgressSpinnerModule, | ||
| AdminBreadcrumbModule, | ||
| MatSelectModule, | ||
| MatOptionModule, | ||
| MatTooltipModule, | ||
| ], | ||
| exports: [ | ||
| EventDashboardComponent | ||
| ], | ||
| providers: [ | ||
| EventService | ||
| ] | ||
| }) | ||
| export class AdminEventsModule { } |
56 changes: 56 additions & 0 deletions
56
web-app/admin/src/app/admin/admin-event/create-event/create-event.component.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| <div class="dialog-modal"> | ||
| <div class="dialog-header"> | ||
| <h2 class="dialog-title">Create a New Event</h2> | ||
| </div> | ||
|
|
||
| <div class="dialog-content"> | ||
| <div *ngIf="errorMessage" class="error-alert"> | ||
| <i class="fa fa-exclamation-triangle"></i> | ||
| <span>{{ errorMessage }}</span> | ||
| </div> | ||
|
|
||
| <form [formGroup]="eventForm" class="event-form"> | ||
| <div class="form-field"> | ||
| <label class="field-label">Event Name</label> | ||
| <input | ||
| type="text" | ||
| class="form-input" | ||
| formControlName="name" | ||
| placeholder="Enter event name" | ||
| /> | ||
| <div | ||
| *ngIf=" | ||
| eventForm.get('name').invalid && | ||
| (eventForm.get('name').touched || eventForm.get('name').dirty) | ||
| " | ||
| class="field-error" | ||
| > | ||
| <i class="fa fa-exclamation-circle"></i> | ||
| Name is required | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="form-field"> | ||
| <label class="field-label">Description</label> | ||
| <textarea | ||
| class="form-input" | ||
| formControlName="description" | ||
| rows="3" | ||
| placeholder="Enter event description (optional)" | ||
| ></textarea> | ||
| </div> | ||
| </form> | ||
| </div> | ||
|
|
||
| <div class="dialog-actions"> | ||
| <button class="action-button" (click)="cancel()">Cancel</button> | ||
| <button | ||
| class="action-button btn-primary" | ||
| (click)="save()" | ||
| [disabled]="eventForm.invalid" | ||
| > | ||
| <i class="fa fa-save"></i> | ||
| Create Event | ||
| </button> | ||
| </div> | ||
| </div> |
99 changes: 99 additions & 0 deletions
99
web-app/admin/src/app/admin/admin-event/create-event/create-event.component.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| .error-alert { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 0.5rem; | ||
| padding: 1rem; | ||
| background-color: #fef2f2; | ||
| border: 1px solid #fecaca; | ||
| border-radius: 8px; | ||
| margin-bottom: 1.5rem; | ||
| color: #dc2626; | ||
| font-size: 0.875rem; | ||
|
|
||
| i { | ||
| flex-shrink: 0; | ||
| font-size: 1rem; | ||
| } | ||
| } | ||
|
|
||
| .event-form { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1.5rem; | ||
| } | ||
|
|
||
| .form-field { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.5rem; | ||
|
|
||
| .field-label { | ||
| font-size: 0.875rem; | ||
| font-weight: 600; | ||
| color: #374151; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.05em; | ||
| } | ||
|
|
||
| .form-input { | ||
| width: 100%; | ||
| padding: 0.75rem 1rem; | ||
| border: 1px solid #d1d5db; | ||
| border-radius: 8px; | ||
| font-size: 0.875rem; | ||
| background-color: #f9fafb; | ||
| transition: all 0.2s ease; | ||
| resize: vertical; | ||
|
|
||
| &:focus { | ||
| outline: none; | ||
| border-color: #3b82f6; | ||
| background-color: white; | ||
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); | ||
| } | ||
|
|
||
| &::placeholder { | ||
| color: #9ca3af; | ||
| } | ||
|
|
||
| &:disabled { | ||
| background-color: #f3f4f6; | ||
| color: #9ca3af; | ||
| cursor: not-allowed; | ||
| } | ||
| } | ||
|
|
||
| .field-error { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 0.25rem; | ||
| color: #dc2626; | ||
| font-size: 0.75rem; | ||
| margin-top: 0.25rem; | ||
|
|
||
| i { | ||
| font-size: 0.75rem; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| ::ng-deep .mat-dialog-container { | ||
| padding: 0; | ||
| border-radius: 12px; | ||
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04) !important; | ||
| } | ||
|
|
||
| ::ng-deep .mat-dialog-actions { | ||
| padding: 0; | ||
| margin: 0; | ||
| } | ||
|
|
||
| ::ng-deep .mat-dialog-content { | ||
| padding: 0; | ||
| margin: 0; | ||
| } | ||
|
|
||
| ::ng-deep .mat-dialog-title { | ||
| padding: 0; | ||
| margin: 0; | ||
| } |
65 changes: 65 additions & 0 deletions
65
web-app/admin/src/app/admin/admin-event/create-event/create-event.component.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { Component, Inject } from '@angular/core'; | ||
| import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; | ||
| import { FormBuilder, FormGroup, Validators } from '@angular/forms'; | ||
| import { EventsService } from '../events.service'; | ||
| import { Event } from 'src/app/filter/filter.types'; | ||
|
|
||
| /** | ||
| * Dialog component for creating new events. | ||
| * Provides a form interface with validation for event name (required) and description (optional). | ||
| */ | ||
| @Component({ | ||
| selector: 'mage-admin-event-create', | ||
| templateUrl: './create-event.component.html', | ||
| styleUrls: ['./create-event.component.scss'] | ||
| }) | ||
| export class CreateEventDialogComponent { | ||
| eventForm: FormGroup; | ||
| errorMessage: string = ''; | ||
|
|
||
| constructor( | ||
| public dialogRef: MatDialogRef<CreateEventDialogComponent>, | ||
| @Inject(MAT_DIALOG_DATA) public data: { event: Partial<Event> }, | ||
| private fb: FormBuilder, | ||
| private eventsService: EventsService | ||
| ) { | ||
| this.eventForm = this.fb.group({ | ||
| name: [data.event?.name || '', [Validators.required]], | ||
| description: [data.event?.description || ''] | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Handles form submission for creating a new event. | ||
| * Validates the form, creates the event via the events service, and closes the dialog on success. | ||
| */ | ||
| save(): void { | ||
| if (this.eventForm.invalid) { | ||
| this.errorMessage = 'Please fill in all required fields.'; | ||
| return; | ||
| } | ||
|
|
||
| this.errorMessage = ''; | ||
| const eventData = this.eventForm.value; | ||
| this.eventsService.createEvent(eventData).subscribe({ | ||
| next: (newEvent) => { | ||
| this.dialogRef.close(newEvent); | ||
| }, | ||
| error: (err) => { | ||
| if (err.status === 409) { | ||
| this.errorMessage = err.error; | ||
| } | ||
| else { | ||
| this.errorMessage = 'Failed to create event. Please try again.'; | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Closes the dialog without saving any data or making any changes. | ||
| */ | ||
| cancel(): void { | ||
| this.dialogRef.close(); | ||
| } | ||
| } | ||
101 changes: 101 additions & 0 deletions
101
web-app/admin/src/app/admin/admin-event/dashboard/event-dashboard.component.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| <admin-breadcrumb [breadcrumbs]="breadcrumbs"></admin-breadcrumb> | ||
|
|
||
| <div class="container bottom-gap-l"> | ||
| <div class="page-header"> | ||
| <h2 class="page-title">Events</h2> | ||
| </div> | ||
|
|
||
| <div class="table-wrapper mat-elevation-z2"> | ||
| <!-- Top Bar --> | ||
| <div | ||
| class="integrated-navbar d-flex align-items-center justify-content-between" | ||
| > | ||
| <div class="filters d-flex align-items-center"> | ||
| <mage-card-navbar | ||
| [isSearchable]="true" | ||
| searchPlaceholder="Search Events..." | ||
| (searchTermChanged)="onSearchTermChanged($event)" | ||
| (searchCleared)="onSearchCleared()" | ||
| ></mage-card-navbar> | ||
|
|
||
| <mat-form-field appearance="outline" class="ml-3 status-filter"> | ||
| <mat-label>Status</mat-label> | ||
| <mat-select | ||
| [(ngModel)]="eventStatusFilter" | ||
| (selectionChange)="onStatusFilterChange($event.value)" | ||
| > | ||
| <mat-option value="all">All</mat-option> | ||
| <mat-option value="active">Active</mat-option> | ||
| <mat-option value="complete">Complete</mat-option> | ||
| </mat-select> | ||
| </mat-form-field> | ||
| </div> | ||
|
|
||
| <button | ||
| *ngIf="hasEventCreatePermission" | ||
| mat-flat-button | ||
| color="primary" | ||
| (click)="createEvent()" | ||
| > | ||
| New Event | ||
| </button> | ||
| </div> | ||
|
|
||
| <!-- Event Table --> | ||
| <div class="table-scroll" *ngIf="filteredEvents?.length; else noEvents"> | ||
| <table | ||
| mat-table | ||
| [dataSource]="filteredEvents" | ||
| class="mat-table-even-columns mat-table" | ||
| > | ||
| <ng-container matColumnDef="event"> | ||
| <th mat-header-cell *matHeaderCellDef>Event</th> | ||
| <td mat-cell *matCellDef="let event"> | ||
| <div class="d-flex align-items-center pointer"> | ||
| <i class="icon fa fa-calendar mr-2" aria-hidden="true"></i> | ||
| <div class="w-100"> | ||
| <div class="strong">{{ event.name }}</div> | ||
| <div | ||
| [matTooltip]="event.description" | ||
| [matTooltipDisabled]=" | ||
| !event.description || event.description.length <= numChars | ||
| " | ||
| matTooltipClass="mat-tooltip-event-desc" | ||
| class="w-90" | ||
| > | ||
| <p class="muted ellipsis">{{ event.description }}</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </td> | ||
| </ng-container> | ||
|
|
||
| <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> | ||
| <tr | ||
| mat-row | ||
| *matRowDef="let row; columns: displayedColumns" | ||
| class="pointer" | ||
| (click)="gotoEvent(row)" | ||
| ></tr> | ||
| </table> | ||
| </div> | ||
|
|
||
| <!-- Empty State --> | ||
| <ng-template #noEvents> | ||
| <div class="text-center p-4 muted">No events found.</div> | ||
| </ng-template> | ||
|
|
||
| <!-- Pagination --> | ||
| <div class="pagination"> | ||
| <mat-paginator | ||
| [length]="totalEvents" | ||
| [pageSize]="searchOptions.page_size" | ||
| [pageIndex]="searchOptions.page" | ||
| [pageSizeOptions]="pageSizeOptions" | ||
| showFirstLastButtons | ||
| (page)="onPageChange($event)" | ||
| > | ||
| </mat-paginator> | ||
| </div> | ||
| </div> | ||
| </div> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.