From 97ea3b35ca552c0884d085c7669bccea3b11ea54 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Thu, 25 Dec 2025 21:07:40 +0100 Subject: [PATCH] feat(G7): add JoinClub page and no-club dashboard message --- .../Components/Pages/Account/JoinClub.razor | 231 ++++++++++++++++++ .../Components/Pages/Dashboard.razor | 35 ++- 2 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/Koogle.Web/Components/Pages/Account/JoinClub.razor diff --git a/src/Koogle.Web/Components/Pages/Account/JoinClub.razor b/src/Koogle.Web/Components/Pages/Account/JoinClub.razor new file mode 100644 index 0000000..6e78955 --- /dev/null +++ b/src/Koogle.Web/Components/Pages/Account/JoinClub.razor @@ -0,0 +1,231 @@ +@page "/account/join-club" +@attribute [Authorize] + +@using Koogle.Application.DTOs +@using Koogle.Application.Interfaces +@using Microsoft.AspNetCore.Authorization + +@inject IUserService UserService +@inject IClubService ClubService +@inject ISnackbar Snackbar +@inject NavigationManager NavigationManager + +Club beitreten + + + Club beitreten + + @if (_isLoading) + { + + } + else if (_requestSent) + { + + + Dein Beitrittsantrag wurde erfolgreich gesendet! + + + Ein Admin des Clubs wird deinen Antrag pruefen. Du erhaeltst eine Benachrichtigung, sobald dein Antrag bearbeitet wurde. + + + + Weiteren Antrag stellen + + + Zum Profil + + } + else + { + + + Gib den Namen des Clubs ein, dem du beitreten moechtest. Dein Antrag wird vom Club-Admin geprueft. + + + + + + @if (_searchResult is not null) + { + +
+
+ @_searchResult.Name + @_searchResult.MemberCount Mitglieder +
+ +
+
+ } + else if (_searched && !string.IsNullOrWhiteSpace(_clubName)) + { + + Kein Club mit diesem Namen gefunden. Bitte pruefe die Schreibweise. + + } + + @if (!string.IsNullOrEmpty(_error)) + { + @_error + } + +
+ + @if (_isSearching) + { + + } + Club suchen + + + + @if (_isSubmitting) + { + + } + Beitrittsantrag senden + +
+
+
+ } +
+ +@code { + private MudForm? _form; + private bool _isValid; + private string _clubName = ""; + private ClubDto? _searchResult; + private bool _searched; + private bool _isLoading; + private bool _isSearching; + private bool _isSubmitting; + private bool _requestSent; + private string? _error; + private UserDto? _currentUser; + + protected override async Task OnInitializedAsync() + { + _isLoading = true; + try + { + _currentUser = await UserService.GetCurrentUserAsync(); + } + finally + { + _isLoading = false; + } + } + + private async Task OnClubNameKeyUp(KeyboardEventArgs e) + { + // Reset search result when user types + if (_searched) + { + _searched = false; + _searchResult = null; + _error = null; + } + + // Search on Enter key + if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(_clubName)) + { + await SearchClub(); + } + } + + private async Task SearchClub() + { + if (string.IsNullOrWhiteSpace(_clubName)) + return; + + _isSearching = true; + _error = null; + _searched = false; + _searchResult = null; + + try + { + _searchResult = await ClubService.GetByNameAsync(_clubName.Trim()); + _searched = true; + + // Check if user is already member + if (_searchResult is not null && _currentUser is not null) + { + var existingMembership = _currentUser.ClubMemberships + .FirstOrDefault(m => m.ClubId == _searchResult.Id); + + if (existingMembership is not null) + { + _error = "Du bist bereits Mitglied dieses Clubs oder hast einen offenen Antrag."; + _searchResult = null; + } + } + } + catch (Exception ex) + { + _error = $"Fehler bei der Suche: {ex.Message}"; + } + finally + { + _isSearching = false; + } + } + + private async Task SubmitRequest() + { + if (_searchResult is null || _currentUser is null) + return; + + _isSubmitting = true; + _error = null; + + try + { + var success = await UserService.RequestClubMembershipAsync( + _currentUser.ProfileId, + _searchResult.Id); + + if (success) + { + _requestSent = true; + Snackbar.Add("Beitrittsantrag erfolgreich gesendet", Severity.Success); + } + else + { + _error = "Der Antrag konnte nicht gesendet werden. Moeglicherweise existiert bereits ein Antrag."; + } + } + catch (Exception ex) + { + _error = $"Fehler beim Senden des Antrags: {ex.Message}"; + } + finally + { + _isSubmitting = false; + } + } + + private void ResetForm() + { + _clubName = ""; + _searchResult = null; + _searched = false; + _requestSent = false; + _error = null; + } +} diff --git a/src/Koogle.Web/Components/Pages/Dashboard.razor b/src/Koogle.Web/Components/Pages/Dashboard.razor index b08a202..3dd6777 100644 --- a/src/Koogle.Web/Components/Pages/Dashboard.razor +++ b/src/Koogle.Web/Components/Pages/Dashboard.razor @@ -1,13 +1,16 @@ @page "/dashboard" -@attribute [Authorize(Policy = "ClubViewer")] +@attribute [Authorize] @using Koogle.Application.DTOs @using Koogle.Application.Interfaces @using Koogle.Domain.Enums +@using Koogle.Infrastructure.Security @using Koogle.Web.Components.Shared @using Microsoft.AspNetCore.Authorization @inject IDashboardService DashboardService +@inject IUserService UserService +@inject ICurrentClubContext CurrentClubContext @inject NavigationManager NavigationManager @inject ISnackbar Snackbar @@ -19,6 +22,21 @@ { } +else if (_hasNoClub) +{ + +
+ + Keinem Club zugeordnet + + Du bist noch keinem Club zugeordnet. Um Koogle zu nutzen, tritt einem bestehenden Club bei. + + + Einem Club beitreten + +
+
+} else if (_error is not null) { @_error @@ -149,6 +167,7 @@ else if (_dashboard is not null) @code { private DashboardDto? _dashboard; private bool _isLoading = true; + private bool _hasNoClub; private string? _error; protected override async Task OnInitializedAsync() @@ -162,6 +181,20 @@ else if (_dashboard is not null) { _isLoading = true; _error = null; + + // Check if user has club context + var clubId = CurrentClubContext.ClubId; + if (clubId == Guid.Empty) + { + // Double-check via user service + var user = await UserService.GetCurrentUserAsync(); + if (user == null || user.ClubMemberships.Count == 0) + { + _hasNoClub = true; + return; + } + } + _dashboard = await DashboardService.GetDashboardAsync(); } catch (Exception ex)