Skip to content

Commit

Permalink
Added pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
NotZetka committed Sep 6, 2024
1 parent e4b1bbd commit 8d530d0
Show file tree
Hide file tree
Showing 18 changed files with 242 additions and 66 deletions.
4 changes: 1 addition & 3 deletions API/Controllers/BodyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ public async Task<ActionResult> AddBodyweightRecord(AddBodyWeightRecordCommand q
}

[HttpGet]
public async Task<ActionResult<GetBodyWeightResponse>> GetBodyWeight()
public async Task<ActionResult<GetBodyWeightResponse>> GetBodyWeight([FromQuery] GetBodyWeightQuery query)
{
var query = new GetBodyWeightQuery();

var result = await _mediator.Send(query);

return Ok(result);
Expand Down
22 changes: 19 additions & 3 deletions API/Data/Repositories/BodyWeight/BodyWeightRepository.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

using API.Data.Dtos;
using API.Utilities;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
Expand All @@ -15,11 +16,26 @@ public void AddRecord(int userId, BodyWeightRecord record)
bodyWeight.WeightRecords.Add(record);
}

public async Task<BodyWeightDto> GetBodyWeightAsync(int userId)
public async Task<PagedResult<BodyWeightRecordDto>> GetBodyWeightRecordsAsync(int userId, int? pageNumber = null, int? pageSize = null)
{
var query = _dbSet
.Where(x => x.UserId == userId)
.SelectMany(x => x.WeightRecords)
.ProjectTo<BodyWeightRecordDto>(_mapper.ConfigurationProvider);

if (pageNumber != null && pageSize != null)
{
return await PagedResult<BodyWeightRecordDto>.CreateFromQueryAsync(query, pageNumber.Value, pageSize.Value);
}

return new PagedResult<BodyWeightRecordDto>(await query.ToListAsync());
}

public async Task<int?> GetHeight(int userId)
{
return await _dbSet
.Where(x=>x.UserId == userId)
.ProjectTo<BodyWeightDto>(_mapper.ConfigurationProvider)
.Where(x => x.UserId == userId)
.Select(x => x.Height)
.FirstOrDefaultAsync();
}

Expand Down
5 changes: 4 additions & 1 deletion API/Data/Repositories/BodyWeight/IBodyWeightRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using API.Data.Dtos;
using API.Utilities;

namespace API.Data.Repositories
{
Expand All @@ -7,6 +8,8 @@ public interface IBodyWeightRepository : IRepository<BodyWeight>
public void SetHeight(int height, int userId);
public void AddRecord(int userId, BodyWeightRecord record);

public Task<BodyWeightDto> GetBodyWeightAsync(int userId);
public Task<int?> GetHeight(int userId);

public Task<PagedResult<BodyWeightRecordDto>> GetBodyWeightRecordsAsync(int userId, int? pageNumber = null, int? pageSize = null);
}
}
1 change: 0 additions & 1 deletion API/Data/Repositories/Users/UsersRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public async Task<PagedResult<UserDto>> GetUsersListAsync(int? pageNumber = null

if(pageNumber != null && pageSize != null)
{
query = query.Skip((pageNumber.Value - 1) * pageSize.Value).Take(pageSize.Value);
return await PagedResult<UserDto>.CreateFromQueryAsync(query, pageNumber.Value, pageSize.Value);
}

Expand Down
2 changes: 1 addition & 1 deletion API/Handlers/Accounts/List/GetAccountsListHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public GetAccountsListHandler(IUnitOfWork unitOfWork)
}
public async Task<PagedResult<UserDto>> Handle(GetAccountsListQuery request, CancellationToken cancellationToken)
{
return await _unitOfWork.UsersRepository.GetUsersListAsync();
return await _unitOfWork.UsersRepository.GetUsersListAsync(request.PageNumber, request.PageSize);
}
}
}
7 changes: 5 additions & 2 deletions API/Handlers/BodyWeight/GetBodyWeight/GetBodyWeightHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ public async Task<GetBodyWeightResponse> Handle(GetBodyWeightQuery request, Canc
{
var user = await _userService.GetCurrentUserAsync();

var bodyWeight = await _unitOfWork.BodyWeightRepository.GetBodyWeightAsync(user.Id);
var height = await _unitOfWork.BodyWeightRepository.GetHeight(user.Id);

var bodyWeight = await _unitOfWork.BodyWeightRepository.GetBodyWeightRecordsAsync(user.Id, request.PageNumber, request.PageSize);

return new GetBodyWeightResponse() {
BodyWeight = bodyWeight,
BodyWeightRecords = bodyWeight,
Height = height,
GenderMale = user.Gender.Equals("male", StringComparison.OrdinalIgnoreCase),
};
}
Expand Down
6 changes: 3 additions & 3 deletions API/Handlers/BodyWeight/GetBodyWeight/GetBodyWeightQuery.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

using API.Data.Dtos;
using MediatR;
using MediatR;

namespace API.Handlers.BodyWeight.GetBodyWeight
{
public class GetBodyWeightQuery : IRequest<GetBodyWeightResponse>
{
public int? PageNumber { get; set; }
public int? PageSize { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using API.Data.Dtos;
using API.Utilities;

namespace API.Handlers.BodyWeight.GetBodyWeight
{
public class GetBodyWeightResponse
{
public bool GenderMale { get; set; }
public BodyWeightDto BodyWeight { get; set; }
public int? Height { get; set; }
public PagedResult<BodyWeightRecordDto> BodyWeightRecords { get; set; }
}
}
7 changes: 5 additions & 2 deletions API/Utilities/PagedResult.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace API.Utilities
{
public class PagedResult<T>
{
public PagedResult() {}
public PagedResult(List<T> items)
{
Items = items;
Expand All @@ -26,9 +28,10 @@ public PagedResult(List<T> items, int totalPages, int totalCount, int itemsFrom,
public int TotalCount { get; set; }
public int ItemsFrom { get; set; }
public int ItemsTo { get; set; }
public static async Task<PagedResult<T>> CreateFromQueryAsync(IQueryable<T> items, int pageNumber, int pageSize)
public static async Task<PagedResult<T>> CreateFromQueryAsync(IQueryable<T> query, int pageNumber, int pageSize)
{
var totalCount = items.Count();
var totalCount = query.Count();
var items = query.Skip((pageNumber - 1) * pageSize).Take(pageSize);
var toatlPages = (int)Math.Ceiling(totalCount / (double)pageSize);
var itemsFrom = (pageNumber - 1) * pageSize + 1;
var itemsTo = itemsFrom + pageSize - 1 < totalCount ? itemsFrom + pageSize - 1 : totalCount;
Expand Down
24 changes: 21 additions & 3 deletions client/src/app/Accounts/list/accounts-list.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
<div class="row">
<div class="col-2" *ngFor="let user of users">
<app-user-card [user]="user"></app-user-card>
<p class="text-center my-4 fs-5">Users from {{itemsFrom}} to {{itemsTo}} of {{totalCount}}</p>

<div class="row justify-content-center align-items-center g-3">
<div class="col-10 col-sm-6 col-md-4 col-lg-3 col-xl-2" *ngFor="let user of users">
<app-user-card [user]="user" class="shadow-sm rounded mb-4"></app-user-card>
</div>
</div>

<p class="text-center my-3 fs-5">Page {{currentPage}} of {{totalPages}}</p>

<div class="d-flex justify-content-center align-items-center mt-3">
<button class="btn btn-secondary me-2" (click)="previousPage()" [disabled]="currentPage === 1">Previous</button>
<input
type="number"
class="form-control text-center me-2"
style="width: 80px;"
[(ngModel)]="currentPage"
(change)="goToPage(currentPage)"
min="1"
[max]="totalPages || 1"
/>
<button class="btn btn-secondary" (click)="nextPage()" [disabled]="currentPage === totalPages">Next</button>
</div>
37 changes: 35 additions & 2 deletions client/src/app/Accounts/list/accounts-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,49 @@ import {environment} from "../../../environments/environment";
})
export class AccountsListComponent implements OnInit {
baseUrl = environment.baseUrl;
users : UserDto[] = new Array<UserDto>()
users : UserDto[] = new Array<UserDto>();
totalPages?: number;
totalCount?: number;
itemsFrom?: number;
itemsTo?: number;
pageSize: number = 10;
currentPage: number = 1;

constructor(private http: HttpClient) {
}

ngOnInit(): void {
this.http.get<GetAccountsListResponse>(this.baseUrl+'Accounts/List/').subscribe({
this.getList(this.currentPage,this.pageSize)
}

private getList(pageNumber: number, pageSize: number): void{
this.http.get<GetAccountsListResponse>(this.baseUrl+'Accounts/List?' + 'PageNumber=' + pageNumber + '&PageSize=' + pageSize).subscribe({
next: response => {
this.users = response.items;
this.totalPages = response.totalPages;
this.totalCount = response.totalCount;
this.itemsFrom = response.itemsFrom;
this.itemsTo = response.itemsTo;
this.currentPage = pageNumber;
}
})
}

goToPage(pageNumber: number): void {
if (pageNumber >= 1 && pageNumber <= (this.totalPages || 1)) {
this.getList(pageNumber, this.pageSize);
}
}

nextPage(): void {
if (this.currentPage < (this.totalPages || 1)) {
this.goToPage(this.currentPage + 1);
}
}

previousPage(): void {
if (this.currentPage > 1) {
this.goToPage(this.currentPage - 1);
}
}
}
20 changes: 15 additions & 5 deletions client/src/app/Body/body-main/body-main.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<div class="container">
<ng-container *ngIf="bodyWeight">
<div *ngIf="!isLoaded" class="text-center">
<p>Loading data...</p>
</div>

<ng-container *ngIf="isLoaded && bodyWeightRecords">
<div class="text-center" *ngIf="!isEditingHeight; else heightInput">
<p class="text-light bg-dark p-2 rounded">Height: {{bodyWeight.height}}</p>
<p class="text-light bg-dark p-2 rounded">Height: {{height}}</p>
<button class="btn btn-primary mt-2" (click)="enableHeightEdit()">Change</button>
</div>
<ng-template #heightInput>
Expand All @@ -24,14 +28,20 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let record of bodyWeight.weightRecords">
<tr *ngFor="let record of bodyWeightRecords.items">
<td>{{record.date | date}}</td>
<td>{{record.weight}}</td>
<td>{{ calculateBMI(record.weight, bodyWeight.height) }}</td>
<td>{{ getStatus(record.weight, bodyWeight.height) }}</td>
<td>{{ calculateBMI(record.weight, height) }}</td>
<td>{{ getStatus(record.weight, height) }}</td>
<td><button class="btn btn-secondary" (click)="viewDetails(record)">Details</button></td>
</tr>
</tbody>
</table>

<div class="d-flex justify-content-between mt-4">
<button class="btn btn-secondary" (click)="goToPreviousPage()" [disabled]="currentPage === 1">Previous</button>
<span>Page {{currentPage}} of {{bodyWeightRecords.totalPages}}</span>
<button class="btn btn-secondary" (click)="goToNextPage()" [disabled]="currentPage === bodyWeightRecords.totalPages">Next</button>
</div>
</ng-container>
</div>
49 changes: 39 additions & 10 deletions client/src/app/Body/body-main/body-main.component.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,59 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { BodyService } from '../../_services/body.service';
import { BodyWeight } from '../models/BodyWeight';
import {BodyWeightRecord} from "../models/BodyWeightRecord";
import {PagedResult} from "../../_common/PagedResult";

@Component({
selector: 'app-body-main',
templateUrl: './body-main.component.html',
styleUrls: ['./body-main.component.css']
})
export class BodyMainComponent implements OnInit {
bodyWeight?: BodyWeight;
bodyWeightRecords?: PagedResult<BodyWeightRecord>;
height?: number;
genderMale: boolean = false;
isEditingHeight: boolean = true;
newHeight?: number;
isLoaded: boolean = false;
currentPage = 1;
pageSize = 10;

constructor(private bodyService: BodyService, private router: Router) {}

ngOnInit(): void {
this.bodyService.getBodyWeight().subscribe({
this.loadBodyWeightRecords(this.currentPage, this.pageSize)
}

loadBodyWeightRecords(pageNumber: number, pageSize: number): void {
this.bodyService.getBodyWeight(pageNumber, pageSize).subscribe({
next: response => {
this.bodyWeight = response.bodyWeight;
if (this.bodyWeight.height) {
this.bodyWeightRecords = response.bodyWeightRecords;
console.log(this.bodyWeightRecords);
if (response.height) {
this.height = response.height;
this.isEditingHeight = false;
}
this.genderMale = response.genderMale;
this.isLoaded = true;
},
error: () => {
this.isLoaded = false;
}
});
}

enableHeightEdit(): void {
this.isEditingHeight = true;
this.newHeight = this.bodyWeight?.height || undefined;
this.newHeight = this.height || undefined;
}

saveHeight(): void {
if (this.newHeight != null) {
this.bodyService.saveHeight(this.newHeight).subscribe({
next: () => {
if (this.bodyWeight && this.newHeight) {
this.bodyWeight.height = this.newHeight;
if (this.bodyWeightRecords && this.newHeight) {
this.height = this.newHeight;
}
this.isEditingHeight = !this.isEditingHeight;
}
Expand Down Expand Up @@ -66,10 +81,24 @@ export class BodyMainComponent implements OnInit {
}

addRecord(): void {
this.router.navigate(['/body-record-details'], { queryParams: { genderMale: this.genderMale, height: this.bodyWeight?.height, isViewMode: false } });
this.router.navigate(['/body-record-details'], { queryParams: { genderMale: this.genderMale, height: this.height, isViewMode: false } });
}

viewDetails(record: any): void {
this.router.navigate(['/body-record-details'], { queryParams: { ...record, genderMale: this.genderMale, height: this.bodyWeight?.height, isViewMode: true } });
this.router.navigate(['/body-record-details'], { queryParams: { ...record, genderMale: this.genderMale, height: this.height, isViewMode: true } });
}

goToPreviousPage(): void {
if (this.currentPage > 1) {
this.currentPage--;
this.loadBodyWeightRecords(this.currentPage, this.pageSize);
}
}

goToNextPage(): void {
if (this.bodyWeightRecords && this.currentPage < this.bodyWeightRecords.totalPages) {
this.currentPage++;
this.loadBodyWeightRecords(this.currentPage, this.pageSize);
}
}
}
6 changes: 4 additions & 2 deletions client/src/app/Body/models/GetBodyWeightQueryResponse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {BodyWeight} from "./BodyWeight";
import {BodyWeightRecord} from "./BodyWeightRecord";
import {PagedResult} from "../../_common/PagedResult";

export interface GetBodyWeightQueryResponse {
bodyWeight: BodyWeight;
bodyWeightRecords: PagedResult<BodyWeightRecord>
height: number;
genderMale: boolean;
}
Loading

0 comments on commit 8d530d0

Please sign in to comment.