generated from nhcarrigan/template
feat: pagination
This commit is contained in:
@@ -4,17 +4,18 @@
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
||||
import { Component, OnInit, inject, signal, computed } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { SuggestionService } from '../../services/suggestion.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { PaginationComponent } from '../shared/pagination.component';
|
||||
import { Suggestion, SuggestionStatus, SuggestionEntity } from '@library/shared-types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-suggestions',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule],
|
||||
imports: [CommonModule, FormsModule, PaginationComponent],
|
||||
template: `
|
||||
<div class="container">
|
||||
<div class="header-section">
|
||||
@@ -65,8 +66,16 @@ import { Suggestion, SuggestionStatus, SuggestionEntity } from '@library/shared-
|
||||
<p>No suggestions found.</p>
|
||||
</div>
|
||||
} @else {
|
||||
<app-pagination
|
||||
[currentPage]="currentPage()"
|
||||
[pageSize]="pageSize()"
|
||||
[totalItems]="totalFilteredSuggestions()"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
></app-pagination>
|
||||
|
||||
<div class="suggestions-list">
|
||||
@for (suggestion of filteredSuggestions(); track suggestion.id) {
|
||||
@for (suggestion of paginatedSuggestions(); track suggestion.id) {
|
||||
<div class="suggestion-card" [class]="'status-' + suggestion.status.toLowerCase()">
|
||||
<div class="suggestion-header">
|
||||
<div class="badges">
|
||||
@@ -185,6 +194,14 @@ import { Suggestion, SuggestionStatus, SuggestionEntity } from '@library/shared-
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<app-pagination
|
||||
[currentPage]="currentPage()"
|
||||
[pageSize]="pageSize()"
|
||||
[totalItems]="totalFilteredSuggestions()"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
></app-pagination>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,19 +549,32 @@ export class AdminSuggestionsComponent implements OnInit {
|
||||
decliningsuggestion = signal<Suggestion | null>(null);
|
||||
declineReason = '';
|
||||
|
||||
// Pagination state
|
||||
currentPage = signal(1);
|
||||
pageSize = signal(25);
|
||||
|
||||
SuggestionStatus = SuggestionStatus;
|
||||
|
||||
unreviewedCount = () => this.suggestions().filter(s => s.status === SuggestionStatus.UNREVIEWED).length;
|
||||
acceptedCount = () => this.suggestions().filter(s => s.status === SuggestionStatus.ACCEPTED).length;
|
||||
declinedCount = () => this.suggestions().filter(s => s.status === SuggestionStatus.DECLINED).length;
|
||||
|
||||
filteredSuggestions = () => {
|
||||
filteredSuggestions = computed(() => {
|
||||
const filter = this.statusFilter();
|
||||
if (filter === 'all') {
|
||||
return this.suggestions();
|
||||
}
|
||||
return this.suggestions().filter(s => s.status === filter);
|
||||
};
|
||||
});
|
||||
|
||||
paginatedSuggestions = computed(() => {
|
||||
const suggestions = this.filteredSuggestions();
|
||||
const start = (this.currentPage() - 1) * this.pageSize();
|
||||
const end = start + this.pageSize();
|
||||
return suggestions.slice(start, end);
|
||||
});
|
||||
|
||||
totalFilteredSuggestions = computed(() => this.filteredSuggestions().length);
|
||||
|
||||
ngOnInit() {
|
||||
if (this.authService.isAdmin()) {
|
||||
@@ -568,6 +598,19 @@ export class AdminSuggestionsComponent implements OnInit {
|
||||
|
||||
setFilter(filter: 'all' | SuggestionStatus) {
|
||||
this.statusFilter.set(filter);
|
||||
this.currentPage.set(1); // Reset to first page when filter changes
|
||||
}
|
||||
|
||||
onPageChange(page: number) {
|
||||
this.currentPage.set(page);
|
||||
}
|
||||
|
||||
onPageSizeChange(pageSize: number) {
|
||||
this.pageSize.set(pageSize);
|
||||
// Calculate new current page to stay on approximately the same content
|
||||
const firstItemIndex = (this.currentPage() - 1) * this.pageSize();
|
||||
const newPage = Math.floor(firstItemIndex / pageSize) + 1;
|
||||
this.currentPage.set(newPage);
|
||||
}
|
||||
|
||||
getStatusLabel(status: SuggestionStatus): string {
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
||||
import { Component, OnInit, inject, signal, computed } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { PaginationComponent } from '../shared/pagination.component';
|
||||
import { User } from '@library/shared-types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-users',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, PaginationComponent],
|
||||
template: `
|
||||
<div class="admin-container">
|
||||
<h2>User Management</h2>
|
||||
@@ -24,8 +25,16 @@ import { User } from '@library/shared-types';
|
||||
} @else if (error()) {
|
||||
<p class="error">{{ error() }}</p>
|
||||
} @else {
|
||||
<app-pagination
|
||||
[currentPage]="currentPage()"
|
||||
[pageSize]="pageSize()"
|
||||
[totalItems]="totalUsers()"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
></app-pagination>
|
||||
|
||||
<div class="users-list">
|
||||
@for (user of users(); track user.id) {
|
||||
@for (user of paginatedUsers(); track user.id) {
|
||||
<div class="user-card" [class.banned]="user.isBanned">
|
||||
<div class="user-info">
|
||||
@if (user.avatar) {
|
||||
@@ -70,6 +79,14 @@ import { User } from '@library/shared-types';
|
||||
<p class="no-users">No users found.</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<app-pagination
|
||||
[currentPage]="currentPage()"
|
||||
[pageSize]="pageSize()"
|
||||
[totalItems]="totalUsers()"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
></app-pagination>
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
@@ -270,6 +287,18 @@ export class AdminUsersComponent implements OnInit {
|
||||
loading = signal(true);
|
||||
error = signal<string | null>(null);
|
||||
|
||||
// Pagination state
|
||||
currentPage = signal(1);
|
||||
pageSize = signal(25);
|
||||
|
||||
paginatedUsers = computed(() => {
|
||||
const start = (this.currentPage() - 1) * this.pageSize();
|
||||
const end = start + this.pageSize();
|
||||
return this.users().slice(start, end);
|
||||
});
|
||||
|
||||
totalUsers = computed(() => this.users().length);
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.authService.isAdmin()) {
|
||||
this.router.navigate(['/']);
|
||||
@@ -320,4 +349,16 @@ export class AdminUsersComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onPageChange(page: number): void {
|
||||
this.currentPage.set(page);
|
||||
}
|
||||
|
||||
onPageSizeChange(pageSize: number): void {
|
||||
this.pageSize.set(pageSize);
|
||||
// Calculate new current page to stay on approximately the same content
|
||||
const firstItemIndex = (this.currentPage() - 1) * this.pageSize();
|
||||
const newPage = Math.floor(firstItemIndex / pageSize) + 1;
|
||||
this.currentPage.set(newPage);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user