From 1b90b0119d14eb0db7cb92e303a5d142529330cf Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Mon, 30 Mar 2026 11:41:40 +0700 Subject: [PATCH] fix(staff): fix staff/me profile resolution and add POS access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: BFF GetMyStaffProfile used ExtractUserIdFromJwt(authHeader) which reads Authorization header — but BFF uses httpOnly cookie auth, so authHeader was always null → userId match always failed → 404. Fix: Extract userId/email from bff_session cookie instead. Also add email fallback matching when userId match fails. Additionally: - Add "Mở POS" button on Staff Dashboard (orange, links to POS page) - Add "Mở POS" link in StaffLayout sidebar for Cashier/Manager roles - POS link uses shopId from staff's shopAssignment Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Layout/StaffLayout.razor | 6 ++-- .../Pages/Staff/StaffDashboard.razor | 8 ++++++ .../Controllers/StaffController.cs | 28 +++++++++++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/StaffLayout.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/StaffLayout.razor index a4eeef85..7e059c54 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/StaffLayout.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/StaffLayout.razor @@ -57,11 +57,11 @@ Bàn / Order } - @if (_staffRole == "Cashier") + @if (_staffRole == "Cashier" || _staffRole == "Manager") { - + - Thu ngân + Mở POS } @if (_staffRole == "Manager") diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Staff/StaffDashboard.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Staff/StaffDashboard.razor index 0284f2ad..f08d9c6a 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Staff/StaffDashboard.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Staff/StaffDashboard.razor @@ -46,6 +46,14 @@ Xin nghỉ phép + + @if (_profile?.ShopId.HasValue == true) + { + + } @* ═══ STAT CARDS ═══ *@ diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs index e1b718a0..178bcafa 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs +++ b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs @@ -170,8 +170,13 @@ public class StaffController : ControllerBase public async Task GetMyStaffProfile() { // EN: Get all staff for this merchant — AuthForwardingHandler auto-forwards the Bearer token. + // Fallback: if merchant-service rejects (staff user is not owner), try staff lookup by email. // VI: Lấy tất cả nhân viên của merchant — AuthForwardingHandler tự động chuyển tiếp Bearer token. + // Fallback: nếu merchant-service từ chối (staff user không phải owner), thử tìm theo email. var authHeader = Request.Headers["Authorization"].FirstOrDefault(); + var (currentUserId, currentEmail) = ExtractUserClaimsFromJwt( + Request.Cookies.TryGetValue("bff_session", out var cookie) ? $"Bearer {cookie}" : authHeader); + var staffResp = await _merchant.GetAsync("/api/v1/merchants/me/staff"); if (!staffResp.IsSuccessStatusCode) return StatusCode((int)staffResp.StatusCode, await staffResp.Content.ReadAsStringAsync()); @@ -191,9 +196,11 @@ public class StaffController : ControllerBase else return NotFound(new { success = false, message = "No staff data found" }); - // EN: Extract userId from JWT 'sub' claim to match staff by userId. - // VI: Trích userId từ JWT 'sub' claim để match nhân viên theo userId. - var userId = ExtractUserIdFromJwt(authHeader); + // EN: Use userId + email already extracted from session cookie (line 177-178). + // Previous bug: ExtractUserIdFromJwt(authHeader) used Authorization header which is null for cookie-based BFF auth. + // VI: Dùng userId + email đã extract từ session cookie (dòng 177-178). + // Bug trước: ExtractUserIdFromJwt(authHeader) dùng Authorization header mà null khi dùng cookie-based BFF auth. + var userId = currentUserId; // EN: Find matching staff member by userId, then by email fallback // VI: Tìm nhân viên khớp theo userId, fallback theo email @@ -211,6 +218,21 @@ public class StaffController : ControllerBase } } + // EN: Fallback: match by email if userId match failed + // VI: Fallback: match theo email nếu userId không khớp + if (matchedStaff == null && !string.IsNullOrEmpty(currentEmail) && items.ValueKind == JsonValueKind.Array) + { + foreach (var staff in items.EnumerateArray()) + { + if (staff.TryGetProperty("email", out var emailProp) && + string.Equals(emailProp.GetString(), currentEmail, StringComparison.OrdinalIgnoreCase)) + { + matchedStaff = staff; + break; + } + } + } + if (matchedStaff == null) return NotFound(new { success = false, message = "Staff profile not found for current user" });