after refactor cleanup
This commit is contained in:
42
DiunaBI.UI.Shared/Components/AuthGuard.razor
Normal file
42
DiunaBI.UI.Shared/Components/AuthGuard.razor
Normal file
@@ -0,0 +1,42 @@
|
||||
@using DiunaBI.UI.Shared.Services
|
||||
@inject AuthService AuthService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<div class="d-flex justify-center align-center" style="height: 100vh;">
|
||||
<MudProgressCircular Indeterminate="true" Size="Size.Large" />
|
||||
</div>
|
||||
}
|
||||
else if (_isAuthenticated)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
private bool _isLoading = true;
|
||||
private bool _isAuthenticated = false;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
Console.WriteLine("AuthGuard: Checking authentication...");
|
||||
|
||||
_isAuthenticated = await AuthService.CheckAuthenticationAsync();
|
||||
_isLoading = false;
|
||||
|
||||
Console.WriteLine($"AuthGuard: isAuthenticated={_isAuthenticated}");
|
||||
|
||||
if (!_isAuthenticated)
|
||||
{
|
||||
Console.WriteLine("AuthGuard: Redirecting to /login");
|
||||
Navigation.NavigateTo("/login", replace: true);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
DiunaBI.UI.Shared/Components/Dashboard.razor
Normal file
42
DiunaBI.UI.Shared/Components/Dashboard.razor
Normal file
@@ -0,0 +1,42 @@
|
||||
@page "/dashboard"
|
||||
@using DiunaBI.UI.Shared.Services
|
||||
@using MudBlazor
|
||||
@inject AuthService AuthService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@if (AuthService.IsAuthenticated && AuthService.CurrentUser != null)
|
||||
{
|
||||
<MudCard Class="mt-4" Elevation="2">
|
||||
<MudCardHeader>
|
||||
<CardHeaderAvatar>
|
||||
@if (!string.IsNullOrEmpty(AuthService.CurrentUser.AvatarUrl))
|
||||
{
|
||||
<MudAvatar Size="Size.Large" Style="background: transparent;">
|
||||
<img src="@AuthService.CurrentUser.AvatarUrl" alt="Avatar" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;" />
|
||||
</MudAvatar>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAvatar Color="Color.Primary" Size="Size.Large">
|
||||
@(AuthService.CurrentUser.FullName.Length > 0 ? AuthService.CurrentUser.FullName.Substring(0, 1) : "?")
|
||||
</MudAvatar>
|
||||
}
|
||||
</CardHeaderAvatar>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">@AuthService.CurrentUser.FullName</MudText>
|
||||
<MudText Typo="Typo.body2">@AuthService.CurrentUser.Email</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2">
|
||||
✅ Signed in via Google
|
||||
</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Class="mt-4">
|
||||
You are not logged in
|
||||
</MudAlert>
|
||||
}
|
||||
15
DiunaBI.UI.Shared/Components/Index.razor
Normal file
15
DiunaBI.UI.Shared/Components/Index.razor
Normal file
@@ -0,0 +1,15 @@
|
||||
@page "/"
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@code
|
||||
{
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
Navigation.NavigateTo("/dashboard");
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
}
|
||||
72
DiunaBI.UI.Shared/Components/LayerListComponent.razor
Normal file
72
DiunaBI.UI.Shared/Components/LayerListComponent.razor
Normal file
@@ -0,0 +1,72 @@
|
||||
@using MudBlazor.Internal
|
||||
<MudExpansionPanels Class="mb-4">
|
||||
<MudExpansionPanel Icon="@Icons.Material.Filled.FilterList"
|
||||
Text="Filters"
|
||||
Expanded="true">
|
||||
<MudGrid>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudTextField @bind-Value="filterRequest.Search"
|
||||
Label="Search"
|
||||
Placeholder="Name, number..."
|
||||
Immediate="true"
|
||||
DebounceInterval="500"
|
||||
OnDebounceIntervalElapsed="SearchLayers"
|
||||
Clearable="true"/>
|
||||
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
OnClick="ClearFilters"
|
||||
StartIcon="Icons.Material.Filled.Clear">
|
||||
Clear filters
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudExpansionPanel>
|
||||
</MudExpansionPanels>
|
||||
|
||||
<MudDivider Class="my-4"></MudDivider>
|
||||
|
||||
<MudTable Items="layers.Items"
|
||||
Dense="true"
|
||||
Hover="true"
|
||||
Loading="isLoading"
|
||||
LoadingProgressColor="Color.Info"
|
||||
OnRowClick="@((TableRowClickEventArgs<LayerDto> args) => OnRowClick(args.Item))"
|
||||
T="LayerDto"
|
||||
Style="cursor: pointer;">
|
||||
<HeaderContent>
|
||||
<MudTh>Name</MudTh>
|
||||
<MudTh>Type</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Name">@context.Name</MudTd>
|
||||
<MudTd DataLabel="Type">@context.Type</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText>No layers to display</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
Loading...
|
||||
</LoadingContent>
|
||||
</MudTable>
|
||||
|
||||
@if (layers.TotalCount > 0)
|
||||
{
|
||||
<MudGrid Class="mt-4" AlignItems="Center.Center">
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.body2">
|
||||
Results @((layers.Page - 1) * layers.PageSize + 1) - @Math.Min(layers.Page * layers.PageSize, layers.TotalCount)
|
||||
of @layers.TotalCount
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" Class="d-flex justify-end">
|
||||
<MudPagination Count="layers.TotalPages"
|
||||
Selected="layers.Page"
|
||||
SelectedChanged="OnPageChanged"
|
||||
ShowFirstButton="true"
|
||||
ShowLastButton="true"/>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
65
DiunaBI.UI.Shared/Components/LayerListComponent.razor.cs
Normal file
65
DiunaBI.UI.Shared/Components/LayerListComponent.razor.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using DiunaBI.UI.Shared.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using DiunaBI.Application.DTOModels;
|
||||
using DiunaBI.Application.DTOModels.Common;
|
||||
using MudBlazor;
|
||||
|
||||
namespace DiunaBI.UI.Shared.Components;
|
||||
|
||||
public partial class LayerListComponent : ComponentBase
|
||||
{
|
||||
[Inject] private LayerService LayerService { get; set; } = default!;
|
||||
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
|
||||
private PagedResult<LayerDto> layers = new();
|
||||
private LayerFilterRequest filterRequest = new();
|
||||
private bool isLoading = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadLayers();
|
||||
}
|
||||
|
||||
private async Task LoadLayers()
|
||||
{
|
||||
isLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
layers = await LayerService.GetLayersAsync(filterRequest);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Loading layers failed: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SearchLayers()
|
||||
{
|
||||
filterRequest.Page = 1;
|
||||
await LoadLayers();
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int page)
|
||||
{
|
||||
filterRequest.Page = page;
|
||||
await LoadLayers();
|
||||
}
|
||||
|
||||
private async Task ClearFilters()
|
||||
{
|
||||
filterRequest = new LayerFilterRequest();
|
||||
await LoadLayers();
|
||||
}
|
||||
|
||||
private void OnRowClick(LayerDto layer)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/layers/{layer.Id}");
|
||||
}
|
||||
}
|
||||
200
DiunaBI.UI.Shared/Components/LoginCard.razor
Normal file
200
DiunaBI.UI.Shared/Components/LoginCard.razor
Normal file
@@ -0,0 +1,200 @@
|
||||
|
||||
@using DiunaBI.UI.Shared.Services
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@inject IJSRuntime JS
|
||||
@inject IConfiguration Configuration
|
||||
@inject AuthService AuthService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IGoogleAuthService? GoogleAuthService
|
||||
|
||||
<MudCard Class="login-card" Elevation="8">
|
||||
<MudCardContent Class="pa-8 d-flex flex-column align-center">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Welcome to DiunaBI</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-6 text-center">
|
||||
Sign in using your Google account
|
||||
</MudText>
|
||||
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
StartIcon="@Icons.Custom.Brands.Google"
|
||||
Size="Size.Large"
|
||||
OnClick="HandleGoogleSignIn"
|
||||
Disabled="@_isLoading">
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressCircular Class="mr-3" Size="Size.Small" Indeterminate="true"></MudProgressCircular>
|
||||
<span>Verifying...</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Sign in with Google</span>
|
||||
}
|
||||
</MudButton>
|
||||
|
||||
@if (!string.IsNullOrEmpty(_errorMessage))
|
||||
{
|
||||
<MudAlert Severity="Severity.Error" Class="mt-4" Dense="true">
|
||||
@_errorMessage
|
||||
</MudAlert>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
|
||||
@code {
|
||||
private bool _isLoading = false;
|
||||
private string _errorMessage = string.Empty;
|
||||
private static LoginCard? _instance;
|
||||
private bool _isInitialized = false;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_instance = this;
|
||||
|
||||
// Initialize JavaScript Google SDK for web (both null service and WebGoogleAuthService)
|
||||
// Skip only for mobile platform-specific auth (MobileGoogleAuthService)
|
||||
var isMobileAuth = GoogleAuthService != null && GoogleAuthService.GetType().Name == "MobileGoogleAuthService";
|
||||
|
||||
if (!isMobileAuth)
|
||||
{
|
||||
await InitializeGoogleSignIn();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("📱 Using platform-specific Google auth service");
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeGoogleSignIn()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_isInitialized) return;
|
||||
|
||||
var clientId = Configuration["GoogleAuth:ClientId"];
|
||||
Console.WriteLine($"🔍 Reading GoogleAuth:ClientId from configuration: '{clientId}'");
|
||||
|
||||
if (string.IsNullOrEmpty(clientId))
|
||||
{
|
||||
_errorMessage = "Google ClientId is not configured in appsettings.";
|
||||
Console.Error.WriteLine("❌ Google ClientId is NULL or EMPTY in configuration!");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"✅ Calling initGoogleSignIn with clientId: {clientId}");
|
||||
await JS.InvokeVoidAsync("initGoogleSignIn", clientId);
|
||||
_isInitialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorMessage = "Google Sign-In initialization error.";
|
||||
Console.Error.WriteLine($"❌ Google Sign-In initialization error: {ex.Message}");
|
||||
Console.Error.WriteLine($"Stack trace: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleGoogleSignIn()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isLoading = true;
|
||||
_errorMessage = string.Empty;
|
||||
StateHasChanged();
|
||||
|
||||
// Use platform-specific auth if available (mobile), otherwise use JavaScript (web)
|
||||
if (GoogleAuthService != null)
|
||||
{
|
||||
Console.WriteLine("📱 Using mobile Google auth");
|
||||
var success = await GoogleAuthService.SignInAsync();
|
||||
|
||||
if (success)
|
||||
{
|
||||
Console.WriteLine("✅ Mobile auth successful, navigating...");
|
||||
NavigationManager.NavigateTo("/dashboard", replace: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_errorMessage = "Login failed. Please try again";
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("🌐 Using web JavaScript Google auth");
|
||||
await JS.InvokeVoidAsync("requestGoogleSignIn");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"❌ HandleGoogleSignIn error: {ex.Message}");
|
||||
_errorMessage = "Login error. Please try again";
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public static async Task OnGoogleSignInSuccess(string googleCredential, string fullName, string email, string avatarUrl)
|
||||
{
|
||||
Console.WriteLine($"=== OnGoogleSignInSuccess: {email} ===");
|
||||
|
||||
if (_instance != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Waliduj użytkownika w backendzie DiunaBI
|
||||
var (success, errorMessage) = await _instance.AuthService.ValidateWithBackendAsync(
|
||||
googleCredential, fullName, email, avatarUrl);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Console.WriteLine("✅ User validated, navigating to dashboard");
|
||||
_instance._isLoading = false;
|
||||
_instance._errorMessage = string.Empty;
|
||||
_instance.NavigationManager.NavigateTo("/dashboard", replace: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"❌ Validation failed: {errorMessage}");
|
||||
_instance._isLoading = false;
|
||||
_instance._errorMessage = errorMessage ?? "Login failed.";
|
||||
}
|
||||
|
||||
await _instance.InvokeAsync(() => _instance.StateHasChanged());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"❌ OnGoogleSignInSuccess error: {ex.Message}");
|
||||
_instance._isLoading = false;
|
||||
_instance._errorMessage = "User verification error.";
|
||||
await _instance.InvokeAsync(() => _instance.StateHasChanged());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public static async Task OnGoogleSignInError(string error)
|
||||
{
|
||||
Console.WriteLine($"Google SignIn Error: {error}");
|
||||
|
||||
if (_instance != null)
|
||||
{
|
||||
_instance._isLoading = false;
|
||||
_instance._errorMessage = "Google login error. Please try again";
|
||||
await _instance.InvokeAsync(() => _instance.StateHasChanged());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<style>
|
||||
.login-card {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
</style>
|
||||
10
DiunaBI.UI.Shared/Components/NavMenu.razor
Normal file
10
DiunaBI.UI.Shared/Components/NavMenu.razor
Normal file
@@ -0,0 +1,10 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using MudBlazor
|
||||
<MudNavMenu>
|
||||
<MudNavLink href="dashboard" Icon="@Icons.Material.Filled.Dashboard" Match="NavLinkMatch.All">
|
||||
Dashboard
|
||||
</MudNavLink>
|
||||
<MudNavLink Href="layers" Icon="@Icons.Material.Filled.List" Match="NavLinkMatch.All">
|
||||
Layers
|
||||
</MudNavLink>
|
||||
</MudNavMenu>
|
||||
18
DiunaBI.UI.Shared/Components/Routes.razor
Normal file
18
DiunaBI.UI.Shared/Components/Routes.razor
Normal file
@@ -0,0 +1,18 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using MudBlazor
|
||||
|
||||
<Router AppAssembly="@typeof(Routes).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<MudCard Elevation="0">
|
||||
<MudText Typo="Typo.h6">
|
||||
Strona nieznaleziona.
|
||||
</MudText>
|
||||
</MudCard>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
Reference in New Issue
Block a user