Add sorting functionality to staff playtime table and include roles in UI and database mapping
This commit is contained in:
parent
fb01fc7571
commit
2bc5c41435
|
|
@ -2,5 +2,5 @@ package com.alttd.altitudeweb.database.luckperms;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public record PlayerWithGroup(UUID uuid, String username, String group) {
|
public record PlayerWithGroup(String username, UUID uuid, String group) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ public interface TeamMemberMapper {
|
||||||
|
|
||||||
@ConstructorArgs({
|
@ConstructorArgs({
|
||||||
@Arg(column = "username", javaType = String.class),
|
@Arg(column = "username", javaType = String.class),
|
||||||
@Arg(column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class)
|
@Arg(column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class),
|
||||||
|
@Arg(column = "group", javaType = String.class)
|
||||||
})
|
})
|
||||||
@Select("""
|
@Select("""
|
||||||
SELECT players.username, players.uuid, players.primary_group AS 'group'
|
SELECT players.username, players.uuid, permissions.permission AS 'group'
|
||||||
FROM luckperms_user_permissions AS permissions
|
FROM luckperms_user_permissions AS permissions
|
||||||
INNER JOIN luckperms_players AS players ON players.uuid = permissions.uuid
|
INNER JOIN luckperms_players AS players ON players.uuid = permissions.uuid
|
||||||
WHERE permission IN (${groupPermissions})
|
WHERE permission IN (${groupPermissions})
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,22 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table mat-table [dataSource]="staffPt()" class="mat-elevation-z2 full-width">
|
<table mat-table [dataSource]="sortedStaffPt()" class="mat-elevation-z2 full-width" matSort (matSortChange)="sort.set($event)"
|
||||||
|
[matSortActive]="sort().active" [matSortDirection]="sort().direction" [matSortDisableClear]="true">
|
||||||
<ng-container matColumnDef="staff_member">
|
<ng-container matColumnDef="staff_member">
|
||||||
<th mat-header-cell *matHeaderCellDef>Staff Member</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header="staff_member">Staff Member</th>
|
||||||
<td mat-cell *matCellDef="let row"> {{ row.staff_member }}</td>
|
<td mat-cell *matCellDef="let row"> {{ row.staff_member }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="playtime">
|
<ng-container matColumnDef="playtime">
|
||||||
<th mat-header-cell *matHeaderCellDef>Playtime</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header="playtime">Playtime</th>
|
||||||
<td mat-cell *matCellDef="let row"
|
<td mat-cell *matCellDef="let row"
|
||||||
[style.color]="row.playtime < 420 ? 'red' : ''"> {{ minutesToHm(row.playtime) }}
|
[style.color]="row.playtime < 420 ? 'red' : ''"> {{ minutesToHm(row.playtime) }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="role">
|
<ng-container matColumnDef="role">
|
||||||
<th mat-header-cell *matHeaderCellDef>Rank</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header="role">Rank</th>
|
||||||
<td mat-cell *matCellDef="let row"> {{ row.role }}</td>
|
<td mat-cell *matCellDef="let row"> {{ row.role }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,23 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure good contrast in dark/light modes */
|
||||||
|
.table-theme th.mat-mdc-header-cell,
|
||||||
|
.table-theme td.mat-mdc-cell,
|
||||||
|
.table-theme .mat-mdc-header-row,
|
||||||
|
.table-theme .mat-mdc-row {
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply class to table via HTML's class attribute if needed; here we style all mat tables in this component */
|
||||||
|
table.mat-mdc-table {
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-sort-header-arrow {
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
|
||||||
.no-data td {
|
.no-data td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,15 @@ import {MatTableModule} from '@angular/material/table';
|
||||||
import {MatButtonModule} from '@angular/material/button';
|
import {MatButtonModule} from '@angular/material/button';
|
||||||
import {MatIconModule} from '@angular/material/icon';
|
import {MatIconModule} from '@angular/material/icon';
|
||||||
import {MatTooltipModule} from '@angular/material/tooltip';
|
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||||
|
import {MatSortModule} from '@angular/material/sort';
|
||||||
import {SiteService, StaffPlaytime} from '@api';
|
import {SiteService, StaffPlaytime} from '@api';
|
||||||
|
import {Sort} from '@angular/material/sort';
|
||||||
import {HeaderComponent} from '@header/header.component';
|
import {HeaderComponent} from '@header/header.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-staff-pt',
|
selector: 'app-staff-pt',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, MatTableModule, MatButtonModule, MatIconModule, MatTooltipModule, HeaderComponent],
|
imports: [CommonModule, MatTableModule, MatButtonModule, MatIconModule, MatTooltipModule, MatSortModule, HeaderComponent],
|
||||||
templateUrl: './staff-pt.component.html',
|
templateUrl: './staff-pt.component.html',
|
||||||
styleUrl: './staff-pt.component.scss'
|
styleUrl: './staff-pt.component.scss'
|
||||||
})
|
})
|
||||||
|
|
@ -18,13 +20,31 @@ export class StaffPtComponent implements OnInit {
|
||||||
siteService = inject(SiteService);
|
siteService = inject(SiteService);
|
||||||
|
|
||||||
staffPt = signal<StaffPlaytime[]>([]);
|
staffPt = signal<StaffPlaytime[]>([]);
|
||||||
|
sort = signal<Sort>({active: 'playtime', direction: 'desc'} as Sort);
|
||||||
|
sortedStaffPt = computed<StaffPlaytime[]>(() => {
|
||||||
|
const data = [...this.staffPt()];
|
||||||
|
const {active, direction} = this.sort();
|
||||||
|
if (!direction || !active) return data;
|
||||||
|
const dir = direction === 'asc' ? 1 : -1;
|
||||||
|
return data.sort((a, b) => {
|
||||||
|
switch (active) {
|
||||||
|
case 'staff_member':
|
||||||
|
return a.staff_member.localeCompare(b.staff_member) * dir;
|
||||||
|
case 'role':
|
||||||
|
return a.role.localeCompare(b.role) * dir;
|
||||||
|
case 'playtime':
|
||||||
|
default:
|
||||||
|
return ((a.playtime ?? 0) - (b.playtime ?? 0)) * dir;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
weekStart = signal<Date>(this.getStartOfWeek(new Date()));
|
weekStart = signal<Date>(this.getStartOfWeek(new Date()));
|
||||||
weekEnd = computed(() => this.getEndOfWeek(this.weekStart()));
|
weekEnd = computed(() => this.getEndOfWeek(this.weekStart()));
|
||||||
|
|
||||||
todayStart = signal<Date>(this.startOfDay(new Date()));
|
todayStart = signal<Date>(this.startOfDay(new Date()));
|
||||||
|
|
||||||
displayedColumns = ['staff_member', 'playtime'];
|
displayedColumns = ['staff_member', 'playtime', 'role'];
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadCurrentWeek();
|
this.loadCurrentWeek();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user