From 89f709e07c16894d00d551722fb4b62d403401aa Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 10:24:48 +0100 Subject: [PATCH 1/6] implement pagination --- .../Interfaces/IRestaurantService.cs | 1 + .../Services/RestaurantService.cs | 25 +++ src/DevEats.Web/Pages/Index.razor | 191 +++++++++++++++++- 3 files changed, 210 insertions(+), 7 deletions(-) diff --git a/src/DevEats.Core/Interfaces/IRestaurantService.cs b/src/DevEats.Core/Interfaces/IRestaurantService.cs index 7a63c1e..62a1534 100644 --- a/src/DevEats.Core/Interfaces/IRestaurantService.cs +++ b/src/DevEats.Core/Interfaces/IRestaurantService.cs @@ -6,6 +6,7 @@ public interface IRestaurantService { Task GetByIdAsync(int id); Task> GetAllAsync(); + Task> GetRestaurantsPagedAsync(int pageNumber, int pageSize); Task AddAsync(Restaurant restaurant); Task UpdateAsync(Restaurant restaurant); Task DeleteAsync(int id); diff --git a/src/DevEats.Infrastructure/Services/RestaurantService.cs b/src/DevEats.Infrastructure/Services/RestaurantService.cs index bba2d63..4bfa619 100644 --- a/src/DevEats.Infrastructure/Services/RestaurantService.cs +++ b/src/DevEats.Infrastructure/Services/RestaurantService.cs @@ -29,6 +29,31 @@ public async Task> GetAllAsync() .ToListAsync(); } + public async Task> GetRestaurantsPagedAsync(int pageNumber, int pageSize) + { + if (pageNumber < 1) pageNumber = 1; + if (pageSize < 1) pageSize = 1; + + var query = _context.Restaurants + .Include(r => r.Reviews) + .OrderByDescending(r => r.AverageRating); + + var totalCount = await query.CountAsync(); + + var items = await query + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return new PagedResult + { + Items = items, + TotalCount = totalCount, + PageNumber = pageNumber, + PageSize = pageSize + }; + } + public async Task AddAsync(Restaurant restaurant) { _context.Restaurants.Add(restaurant); diff --git a/src/DevEats.Web/Pages/Index.razor b/src/DevEats.Web/Pages/Index.razor index 77cf98e..624c38f 100644 --- a/src/DevEats.Web/Pages/Index.razor +++ b/src/DevEats.Web/Pages/Index.razor @@ -1,8 +1,7 @@ @page "/" @using DevEats.Core.Models -@using DevEats.Infrastructure.Data -@using Microsoft.EntityFrameworkCore -@inject DevEatsDbContext DbContext +@using DevEats.Core.Interfaces +@inject IRestaurantService RestaurantService @inject NavigationManager Navigation DevEats - Perché il refactoring a stomaco vuoto è pericoloso @@ -108,6 +107,37 @@ } + + @if (totalPages > 1) + { + + } } @@ -434,6 +464,102 @@ } } + /* Pagination Controls */ + .pagination-controls { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + margin-top: 4rem; + padding-top: 2rem; + } + + .pagination-btn { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1.5rem; + background: linear-gradient(135deg, #ff6b6b, #ff8e53); + color: white; + border: none; + border-radius: 12px; + font-weight: 600; + font-size: 1rem; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3); + position: relative; + } + + .pagination-btn:hover:not([disabled]) { + background: linear-gradient(135deg, #ff8e53, #feca57); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4); + } + + /* Enhanced focus indicator for keyboard navigation - WCAG 2.1 AA compliant */ + .pagination-btn:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.4), 0 0 0 5px rgba(255, 255, 255, 1); + } + + .pagination-btn:focus-visible { + outline: 3px solid #ff6b6b; + outline-offset: 2px; + box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.4); + } + + .pagination-btn[disabled] { + background: #cbd5e0; + color: #a0aec0; + cursor: not-allowed; + box-shadow: none; + opacity: 0.6; + } + + /* Improved disabled state contrast - WCAG 2.1 AA minimum 3:1 */ + .pagination-btn[disabled]:focus { + outline: 2px solid #718096; + outline-offset: 2px; + box-shadow: 0 0 0 3px rgba(113, 128, 150, 0.3); + } + + .pagination-btn i { + font-size: 1rem; + } + + .pagination-info { + color: #4a5568; + font-weight: 600; + font-size: 1rem; + min-width: 140px; + text-align: center; + padding: 0.5rem; + } + + /* High contrast mode support */ + @@media (prefers-contrast: high) { + .pagination-btn { + border: 2px solid currentColor; + } + + .pagination-btn:focus { + outline: 4px solid currentColor; + outline-offset: 3px; + } + } + + /* Reduced motion support */ + @@media (prefers-reduced-motion: reduce) { + .pagination-btn { + transition: none; + } + + .pagination-btn:hover:not([disabled]) { + transform: none; + } + } + /* Responsive */ @@media (max-width: 768px) { .hero-title { @@ -451,17 +577,68 @@ .section-title { font-size: 2rem; } + + /* Mobile pagination adjustments */ + .pagination-controls { + gap: 1rem; + flex-wrap: wrap; + } + + .pagination-btn { + padding: 0.625rem 1rem; + font-size: 0.9rem; + min-width: 44px; /* WCAG 2.1 AA minimum touch target size */ + min-height: 44px; + } + + .pagination-info { + min-width: 100px; + font-size: 0.9rem; + } } @code { + [SupplyParameterFromQuery(Name = "page")] + public int PageQuery { get; set; } = 1; + private List? restaurants; + private PagedResult pagedRestaurants = new(); + + private int currentPage = 1; + private const int pageSize = 3; + private int totalPages => pagedRestaurants.TotalPages; protected override async Task OnInitializedAsync() { - restaurants = await DbContext.Restaurants - .Include(r => r.Reviews) - .OrderByDescending(r => r.AverageRating) - .ToListAsync(); + currentPage = PageQuery > 0 ? PageQuery : 1; + await LoadRestaurants(); + } + + protected override async Task OnParametersSetAsync() + { + if (PageQuery != currentPage && PageQuery > 0) + { + currentPage = PageQuery; + await LoadRestaurants(); + } + } + + private async Task LoadRestaurants() + { + pagedRestaurants = await RestaurantService.GetRestaurantsPagedAsync(currentPage, pageSize); + restaurants = pagedRestaurants.Items.ToList(); + } + + private async Task ChangePage(int newPage) + { + if (newPage < 1 || newPage > totalPages || newPage == currentPage) + { + return; + } + + currentPage = newPage; + Navigation.NavigateTo($"/?page={currentPage}"); + await LoadRestaurants(); } } From 743266deb2025e69cd7d140fc5813ce05fd62e92 Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 16:21:21 +0100 Subject: [PATCH 2/6] test github action --- .github/workflows/deploy.yml | 14 +++++++++----- src/DevEats.Web/appsettings.Development2.json | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/DevEats.Web/appsettings.Development2.json diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f158bc7..e6aa317 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,9 +2,9 @@ name: Build and Deploy DevEats on: push: - branches: [ "main", "baseline" ] - pull_request: - branches: [ "main" ] + branches: [ "main", "issues/9" ] + # pull_request: + # branches: [ "issues/*" ] jobs: build-and-test: @@ -39,7 +39,7 @@ jobs: deploy: runs-on: ubuntu-latest needs: build-and-test - if: github.ref == 'refs/heads/main' && github.event_name == 'push' + # if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Download artifact from build job @@ -50,6 +50,10 @@ jobs: - name: Deploy to Azure Web App uses: azure/webapps-deploy@v3 with: - app-name: 'DevEats-WebApp' + app-name: 'deveats-wpc2025-test' publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} package: . + resource-group-name: 'deveats-wpc2025-rg' + env: + ConnectionStrings__DefaultConnection: ${{ secrets.CONNECTION_STRING_TEST }} + diff --git a/src/DevEats.Web/appsettings.Development2.json b/src/DevEats.Web/appsettings.Development2.json new file mode 100644 index 0000000..55da14b --- /dev/null +++ b/src/DevEats.Web/appsettings.Development2.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=localhost,1433;Database=deveats_dev;User Id=sa;Password=DevEats2024!;TrustServerCertificate=True;MultipleActiveResultSets=true" + }, + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} From bb935ca00bf88a66862d4691ebb35a607112a791 Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 17:13:42 +0100 Subject: [PATCH 3/6] add configuration for appsettings.json files --- src/DevEats.Web/Program.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/DevEats.Web/Program.cs b/src/DevEats.Web/Program.cs index c401a66..a66b25a 100644 --- a/src/DevEats.Web/Program.cs +++ b/src/DevEats.Web/Program.cs @@ -7,6 +7,14 @@ var builder = WebApplication.CreateBuilder(args); +// Explicitly configure appsettings.json files +builder.Configuration + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables() + .AddCommandLine(args); + // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); From f73fceca03d32c832b9afc47cdc90fb7863274fb Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 17:33:08 +0100 Subject: [PATCH 4/6] fix --- .claude/commands/start-task.md | 2 +- .github/workflows/deploy.yml | 21 ++++++++++++++++--- note.md | 2 ++ src/DevEats.Web/appsettings.Development2.json | 12 ----------- 4 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 note.md delete mode 100644 src/DevEats.Web/appsettings.Development2.json diff --git a/.claude/commands/start-task.md b/.claude/commands/start-task.md index a668d65..81a519b 100644 --- a/.claude/commands/start-task.md +++ b/.claude/commands/start-task.md @@ -16,4 +16,4 @@ argument-hint: Issue number - Checkout a branch `issues/[issue-number]` starting from the source branch. - Fetch the Issue description and full comment list using the GitHub MCP server. - Push the branch on the remote repository. -- Start coding using csharp-dev passing the Issue description and comments as context. \ No newline at end of file +- Start coding using csharp-dev and accessibility-specialist passing the Issue description and comments as context. \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e6aa317..2955e46 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -47,13 +47,28 @@ jobs: with: name: deveats-app + - name: Azure Login + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Set Azure Web App Settings + run: | + az webapp config appsettings set \ + --name deveats-wpc2025-test \ + --resource-group deveats-wpc2025-rg \ + --settings \ + ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_TEST }}" \ + ASPNETCORE_ENVIRONMENT="Production" + - name: Deploy to Azure Web App uses: azure/webapps-deploy@v3 with: app-name: 'deveats-wpc2025-test' publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} package: . - resource-group-name: 'deveats-wpc2025-rg' - env: - ConnectionStrings__DefaultConnection: ${{ secrets.CONNECTION_STRING_TEST }} + + - name: Azure Logout + run: az logout + if: always() diff --git a/note.md b/note.md new file mode 100644 index 0000000..7537288 --- /dev/null +++ b/note.md @@ -0,0 +1,2 @@ +az ad sp create-for-rbac --name "deveats-wpc2025" --sdk-auth --role contributor \ + --scopes /subscriptions/403624a6-e899-4d2b-95df-ec6353be64a8/resourceGroups/deveats-wpc2025-rg \ No newline at end of file diff --git a/src/DevEats.Web/appsettings.Development2.json b/src/DevEats.Web/appsettings.Development2.json deleted file mode 100644 index 55da14b..0000000 --- a/src/DevEats.Web/appsettings.Development2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "Server=localhost,1433;Database=deveats_dev;User Id=sa;Password=DevEats2024!;TrustServerCertificate=True;MultipleActiveResultSets=true" - }, - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} From c80c4f53bcbea733391c11cb1620ee7162e80d1a Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 17:49:29 +0100 Subject: [PATCH 5/6] wip --- .../workflows/{deploy.yml => deploy-prod.yml} | 9 +-- .github/workflows/deploy-test.yml | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+), 5 deletions(-) rename .github/workflows/{deploy.yml => deploy-prod.yml} (90%) create mode 100644 .github/workflows/deploy-test.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy-prod.yml similarity index 90% rename from .github/workflows/deploy.yml rename to .github/workflows/deploy-prod.yml index 2955e46..603f7a9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy-prod.yml @@ -1,8 +1,8 @@ -name: Build and Deploy DevEats +name: Build and Deploy DevEats in Prod on: push: - branches: [ "main", "issues/9" ] + branches: [ "main"] # pull_request: # branches: [ "issues/*" ] @@ -39,7 +39,6 @@ jobs: deploy: runs-on: ubuntu-latest needs: build-and-test - # if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Download artifact from build job @@ -58,14 +57,14 @@ jobs: --name deveats-wpc2025-test \ --resource-group deveats-wpc2025-rg \ --settings \ - ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_TEST }}" \ + ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_PROD }}" \ ASPNETCORE_ENVIRONMENT="Production" - name: Deploy to Azure Web App uses: azure/webapps-deploy@v3 with: app-name: 'deveats-wpc2025-test' - publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PROD }} package: . - name: Azure Logout diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml new file mode 100644 index 0000000..14429bd --- /dev/null +++ b/.github/workflows/deploy-test.yml @@ -0,0 +1,73 @@ +name: Build and Deploy DevEats in Test + +on: + # push: + # branches: [ "main", "issues/9" ] + pull_request: + branches: [ "issues/*" ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore --configuration Release + + - name: Run Tests + run: dotnet test --no-build --verbosity normal --configuration Release + + - name: Publish + run: dotnet publish src/DevEats.Web/DevEats.Web.csproj -c Release -o ./publish + + - name: Upload artifact for deployment + uses: actions/upload-artifact@v4 + with: + name: deveats-app + path: ./publish + + deploy: + runs-on: ubuntu-latest + needs: build-and-test + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: deveats-app + + - name: Azure Login + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Set Azure Web App Settings + run: | + az webapp config appsettings set \ + --name deveats-wpc2025-test \ + --resource-group deveats-wpc2025-rg \ + --settings \ + ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_TEST }}" \ + ASPNETCORE_ENVIRONMENT="Production" + + - name: Deploy to Azure Web App + uses: azure/webapps-deploy@v3 + with: + app-name: 'deveats-wpc2025-test' + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_TEST }} + package: . + + - name: Azure Logout + run: az logout + if: always() + From ef36f8a0c201206df56c61ac45d81ae5944aecd2 Mon Sep 17 00:00:00 2001 From: Gerardo Greco Date: Wed, 5 Nov 2025 18:03:06 +0100 Subject: [PATCH 6/6] fix --- .github/workflows/deploy-test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml index 14429bd..11a8f7b 100644 --- a/.github/workflows/deploy-test.yml +++ b/.github/workflows/deploy-test.yml @@ -1,10 +1,8 @@ name: Build and Deploy DevEats in Test on: - # push: - # branches: [ "main", "issues/9" ] pull_request: - branches: [ "issues/*" ] + jobs: build-and-test: