diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/MainLayout.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/MainLayout.razor index 70e71e44..0ceee7b2 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/MainLayout.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/MainLayout.razor @@ -1,4 +1,4 @@ -@inherits LayoutComponentBase +@inherits LayoutComponentBase @inject IStringLocalizer L @@ -21,8 +21,8 @@ - @L["Nav_Login"] - @L["Nav_FreeTrial"] + @L["Nav_Login"] + @L["Nav_FreeTrial"] @@ -44,10 +44,10 @@ @L["Nav_Features"] @L["Nav_Pricing"] @L["Nav_Contact"] - @L["Nav_Login"] + @L["Nav_Login"] } diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor index 048eca92..16181cec 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor @@ -1,6 +1,8 @@ @page "/admin" @layout AdminLayout @inherits AdminBase +@inject PosDataService DataService +@using WebClientTpos.Client.Services @* EN: Admin Dashboard — overview of business metrics, stores, alerts, and recent activity. @@ -107,123 +109,47 @@ Cửa hàng của bạn - Quản lý tất cả → + @if (_shops.Count > 0) + { + Quản lý tất cả → + }
- @* Store 1: Coffee House Q1 *@ -
-
-
-
- -
-
-
Coffee House Q1
-
Café • 123 Nguyễn Huệ, Q1
+ @if (_shops.Count == 0) + { +
+ +

Welcome! Tạo cửa hàng đầu tiên

+

Bắt đầu bằng việc tạo cửa hàng để quản lý kinh doanh của bạn.

+ + + Tạo cửa hàng ngay + +
+ } + else + { + @foreach (var shop in _shops) + { +
+
+
+
+ +
+
+
@shop.Name
+
@(shop.Category ?? "Shop") • @(shop.Description ?? shop.Slug)
+
+
+
+ + @(shop.Status == "active" ? "Đang mở" : "Thiết lập") +
-
- - Đang mở -
-
-
-
-
45.2M
-
Doanh thu
-
-
-
342
-
Đơn hàng
-
-
-
5
-
Nhân viên
-
-
-
48
-
Sản phẩm
-
-
-
- - @* Store 2: Nhà hàng Q3 *@ -
-
-
-
- -
-
-
Nhà hàng Q3
-
Restaurant • 456 Lê Văn Sỹ, Q3
-
-
-
- - Đang mở -
-
-
-
-
62.8M
-
Doanh thu
-
-
-
185
-
Đơn hàng
-
-
-
8
-
Nhân viên
-
-
-
72
-
Sản phẩm
-
-
-
- - @* Store 3: Karaoke Star Q7 *@ -
-
-
-
- -
-
-
Karaoke Star Q7
-
Karaoke • 789 Nguyễn Thị Thập, Q7
-
-
-
- - Thiết lập -
-
-
-
-
--
-
Doanh thu
-
-
-
--
-
Đơn hàng
-
-
-
0
-
Nhân viên
-
-
-
0
-
Sản phẩm
-
-
- -
+ } + }
@@ -316,3 +242,34 @@
+ +@code { + private List _shops = new(); + + protected override async Task OnInitializedAsync() + { + IsLoading = true; + try + { + _shops = await DataService.GetShopsAsync(); + } + catch + { + _shops = new(); + } + finally + { + IsLoading = false; + } + } + + private static string GetShopIcon(string? category) => category?.ToLowerInvariant() switch + { + "cafe" or "café" or "coffee" => "coffee", + "restaurant" or "nhà hàng" => "utensils", + "karaoke" => "mic", + "spa" => "sparkles", + "retail" => "shopping-bag", + _ => "store" + }; +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/ForgotPassword.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/ForgotPassword.razor index 7315f14d..89723dcd 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/ForgotPassword.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/ForgotPassword.razor @@ -50,7 +50,7 @@ } diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/LoginCustomer.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/LoginCustomer.razor index c1a32278..65a36209 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/LoginCustomer.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/LoginCustomer.razor @@ -1,5 +1,5 @@ @page "/auth/login/customer" -@page "/login" +@layout AuthLayout @using WebClientTpos.Client.Components.Auth @inherits AuthBase diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/Register.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/Register.razor index c9e24991..6c5fe6ea 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/Register.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/Register.razor @@ -92,7 +92,7 @@ @@ -127,7 +127,7 @@ // EN: Redirect to login after 2 seconds // VI: Chuyển hướng đến đăng nhập sau 2 giây await Task.Delay(2000); - Navigation.NavigateTo("/login"); + Navigation.NavigateTo("/auth/login"); } else { diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/VerifyEmail.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/VerifyEmail.razor index 9b7cc284..bea07f52 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/VerifyEmail.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Auth/VerifyEmail.razor @@ -40,7 +40,7 @@ @message } diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Program.cs b/apps/web-client-tpos-net/src/WebClientTpos.Client/Program.cs index db681304..e2fbb2bf 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Program.cs +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Program.cs @@ -20,6 +20,10 @@ builder.Services.AddSingleton(sp => new HttpClient { BaseAddress = new Uri(new U // VI: Thêm POS data service cho BFF API calls builder.Services.AddScoped(); +// EN: Add auth state service for role-based redirects +// VI: Thêm auth state service cho điều hướng theo vai trò +builder.Services.AddSingleton(); + // EN: Add MudBlazor services // VI: Thêm các services của MudBlazor builder.Services.AddMudServices(); diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthStateService.cs b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthStateService.cs new file mode 100644 index 00000000..94aaa91c --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthStateService.cs @@ -0,0 +1,38 @@ +namespace WebClientTpos.Client.Services; + +public class AuthStateService +{ + public bool IsAuthenticated { get; private set; } + public string? UserEmail { get; private set; } + public string? UserRole { get; private set; } // "owner", "staff", "customer", "branch" + public string? Token { get; private set; } + + public event Action? OnChange; + + public void Login(string email, string token, string role) + { + IsAuthenticated = true; + UserEmail = email; + Token = token; + UserRole = role; + OnChange?.Invoke(); + } + + public void Logout() + { + IsAuthenticated = false; + UserEmail = null; + Token = null; + UserRole = null; + OnChange?.Invoke(); + } + + public string GetPortalUrl() => UserRole switch + { + "owner" or "admin" => "/admin", + "staff" => "/pos/cafe", + "branch" => "/admin", + "customer" => "/app", + _ => "/auth/login" + }; +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Server/Program.cs b/apps/web-client-tpos-net/src/WebClientTpos.Server/Program.cs index 0e4ffd2d..9b8c3c03 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Server/Program.cs +++ b/apps/web-client-tpos-net/src/WebClientTpos.Server/Program.cs @@ -56,12 +56,11 @@ if (app.Environment.IsDevelopment()) { app.MapOpenApi(); app.UseDeveloperExceptionPage(); + app.UseWebAssemblyDebugging(); } app.UseHttpsRedirection(); -// EN: Enable CORS -// VI: Kích hoạt CORS // EN: Enable CORS // VI: Kích hoạt CORS app.UseCors("BlazorClient"); diff --git a/services/iam-service-net/src/IamService.API/keys/is-signing-key-40845B4B36348C1B2FD55311A93F4280.json b/services/iam-service-net/src/IamService.API/keys/is-signing-key-40845B4B36348C1B2FD55311A93F4280.json new file mode 100644 index 00000000..0906e4e0 --- /dev/null +++ b/services/iam-service-net/src/IamService.API/keys/is-signing-key-40845B4B36348C1B2FD55311A93F4280.json @@ -0,0 +1 @@ +{"Version":1,"Id":"40845B4B36348C1B2FD55311A93F4280","Created":"2026-02-26T17:40:10.6713835Z","Algorithm":"RS256","IsX509Certificate":false,"Data":"CfDJ8OE6IQaarJdMrFb-ELKfkmJdiuzUgIT8mztIqfJcZrKHdQw5UiPZvLOdgRvR4ffdcIvMXsaKsH-l0TKza8hmQVhE5RZX2CpQtd_EceQqb4xc7CMzvtCAr6f4HVbbIYtfGOfzzvLPQ2kLhHzoKRVnhFVWKkHswkDekog_H_a6MxDt9WbddI3xuM8c97YA8lsN4hojKfHhKSTE_05eHmXAir6NtMZEgNziU6h99r9EInp7acESdlQ4aUqKapVpDzYb1MTNxxFwggbU_gNlDNwhOZi2-ElWXNJ4pNBwF1ZUjRgydNwdu-qUsYejMkhDPpkX9nXRmU0Hofea-XPDGvcMu5u6YNXB7bRHaY6G1NB1-UGkGbFhM_CQMAuUM8Sp17Zxkgu5YYC9xcWaefdi82xaGl5SGEAV0nfFGZctvqG9YAYR7U2o2hXBOgN2pQuvSdfe4d4IP1KjGa726eVzEMwfzqy-wWpO_UKINHEKEeVHYfhjWvA3zofuCis154kVThw3KFVBOuLCcguF6AqiwXV_veLU-sMaq3sgLwHduxoaNeVZbGAWsqseJC3G1KPjibrQ6Dd1du0uzLMaOUctjPzsDwU4nFpXBUs-pGZuG03vltOJh0U_ankoGW4q5XjsyFQGDFKivdcrufst2DFx_pvD1PtkAawdAoLG9pZy5lrhCxwv_uzDw3pdIK4Q4C-eOpkC-nOsZE3PWfjdA0ouZ09USbj_qeA6mpF0TIafuJTRlz-KkSiy5X4qLWiznGQWO8JmvZGNLx2P8eX_IijhzZaZXknTDRLsmFi5bq1NaEPGvJRPnS_n2E5N2YMC_RBq6ct0pppTnsJaYOip-DPLcA2WUtw_j8QaLD9Y80a0Gv1ky_hU-iivKhUFsvWxvsuJqRFcbFBw5CO-wydUxvDR4ejznen1nAKxh3Jh9b1l26LfMllns9FBcMrTzYYHMkaZFSMXsY-KhaBkcw-46O8aunZlzioxP5oTsaAyI_Ru3jlCJLteCtXoP8c8gpnOsem1praCx6i8n418hmrw1HpK3gdNifrE4fW_M2h5UxzZLzzRZkhvsv_ZgKorpvYH5QrIGzOWUR2DF_wCCTcZbU6PFy0ztTgw_O8NGHi3kAveu_Dff566oWj0oAfNQ0g0lPXnwkK7ZxITHwL47iVhDvEt5OvSR6zTnX4J2J2P3MajQYPkojT3zk5yezEYVp0_hHjQ155f44Q-MoTVaDxJhvF3nN0JXCZ4Xr2wcGiFwGa8OPF0t1H66dapUNwYMfQdPQx8_KiOvSHQUrLtPh-fknasU-dD54TAZotts4zHKRw05W6_7kNaM7mMSCjUd8y1ub2Ae5t0qt1Vt123df-SyBI1vVKFtMPkCpYtTYzgtoR_HEMLUF3bqfoJqXoHvJDBM86DitJYYz-Zcdiukx5rMHSfz6XNQx1m9T8twbXwrowd5K7G3kaDZkXHKtv-Shbsb99gkyq2uHSPDELafyOJfrFQLcoapDuaXCHss8nIhFFZs_YTqs_eGzyUW_tu2fnech-3IO7dlaHmShXJhkE76oEW7eeJCT9WwSbsiSosdU38bCRZeJ05ATIgIdcRGhXF8zeOwEDK-TZvltb0x5JgzQr4BXlPAfi7cQuyyNVLIXz9tyoC0WuFnSS1C1-oJb0ZiW46HpafPzU7eh3is7zwBqv7UkiIZtPUHapJEvxSNNeGM95Mu7h5B1GeoYgurtYfNo4HBkmxsRqsbnEkGuLkfaK33k3ywZZcJx7-BqR_dtzOtdiX0vXcvQr-MnkpleCOKxUr2q0NMjRqOYHAGEdXhWHAqcDhIR5hpx6nFMnCFo2GJu-BpHAJSPQU9OuEWhOgnQmJXM_0NyuaXWQ5xSNGZExKr814ILSTopc56AYHU-AmZQ_Pt2paDcBDj7c3If9N2yo8H_8lxXO1hPBxS7IbJMfMGFDdJrvuHczF1xVzo1x6sYQbRNkezBpIglJXr0GSqwyJ1Ca6BYuCG3_G-jS-MTMkNYiIihZt7OhKtriwZ5YG582R9yyWRfw6YTv_7W-IL1lxdSGFNajXnrtGl513TvQmadqQA1lwjSUtCQYE9b-zXYaFwyn1JdOuJ4fMY2rGdlhODVPot2VGxqVVcjY4c_SN3WHzcxSCcRL-L49oN65OboVMFQ7slH4Gyx4J6gZBMsUFWl_iG5Y55OcfnOgEwbXzjl8yYy69z9NbzrElZ-1h5DlT2QETqWJb1Ujxhwpge-W5RIMxVptNRcBCKVpEhs4VqpKTtUX0v-7srkviEECgfpRAQrCqRZr7CDE6JS7bvOvYdrS0v39z86WhWsxrE7fkxMaoH0mzudU3g9yaD0f5HLjvHmA8VSRugAWi0OQqK7bVysc_q0wFBj6-MQLPD-CBW98X1FMsgVpBNIGeij5He9-iRt3Q9JZbMZakIB2BfnSrkvS9gJ68gfxX_rVhLJs8eF78Ftg1jXdNPZFXOQNqloVym4Oj","DataProtected":true} \ No newline at end of file