-
-
-
-
-
Đơn #2847 hoàn thành
-
Coffee House Q1 • 2 phút trước
-
-
-
-
-
-
Nguyễn Văn A clock-in
-
Nhà hàng Q3 • 5 phút trước
-
-
-
-
-
-
Nhập kho 15 sản phẩm
-
Coffee House Q1 • 12 phút trước
-
-
-
-
-
-
Cập nhật menu buổi tối
-
Nhà hàng Q3 • 28 phút trước
-
-
-
-
-
-
Khách VIP mới: Trần Thị B
-
Hệ thống • 45 phút trước
-
-
+
+
+ API Gateway
+
+ Online
+
+
+
+ IAM Service
+
+ Online
+
+
+
+ Merchant Service
+
+ Online
+
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthService.cs b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthService.cs
index 0965465b..86a9a245 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthService.cs
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/AuthService.cs
@@ -50,7 +50,19 @@ public class AuthService
{
try
{
- var response = await _http.PostAsJsonAsync("/api/auth/register", dto);
+ // EN: Build payload with FirstName/LastName from DisplayName (IAM requires these)
+ // VI: Tạo payload với FirstName/LastName từ DisplayName (IAM yêu cầu)
+ var parts = (dto.DisplayName ?? "User").Trim().Split(' ', 2);
+ var payload = new
+ {
+ dto.Email,
+ dto.Password,
+ FirstName = parts[0],
+ LastName = parts.Length > 1 ? parts[1] : parts[0],
+ DisplayName = dto.DisplayName
+ };
+
+ var response = await _http.PostAsJsonAsync("/api/auth/register", payload);
if (response.IsSuccessStatusCode)
{
return (true, null);
@@ -59,18 +71,32 @@ public class AuthService
var content = await response.Content.ReadAsStringAsync();
try
{
- var error = JsonSerializer.Deserialize
>(content,
- new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
- return (false, error?.Error ?? "Đăng ký thất bại");
+ // EN: Try to parse structured validation errors from IAM
+ // VI: Parse lỗi validation có cấu trúc từ IAM
+ using var doc = JsonDocument.Parse(content);
+ if (doc.RootElement.TryGetProperty("errors", out var errors))
+ {
+ var msgs = new List();
+ foreach (var prop in errors.EnumerateObject())
+ {
+ foreach (var err in prop.Value.EnumerateArray())
+ msgs.Add(err.GetString() ?? prop.Name);
+ }
+ return (false, string.Join("; ", msgs));
+ }
+ if (doc.RootElement.TryGetProperty("title", out var title))
+ return (false, title.GetString());
+
+ return (false, content.Length > 200 ? "Đăng ký thất bại" : content);
}
catch
{
- return (false, content);
+ return (false, "Đăng ký thất bại");
}
}
catch (Exception ex)
{
- return (false, $"Lỗi kết nối: {ex.Message}");
+ return (false, $"Lỗi ({ex.GetType().Name})");
}
}
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/ShopSidebarConfig.cs b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/ShopSidebarConfig.cs
new file mode 100644
index 00000000..348b7fbb
--- /dev/null
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Services/ShopSidebarConfig.cs
@@ -0,0 +1,110 @@
+// EN: Sidebar menu configuration per shop vertical (Café, Restaurant, Karaoke, Spa).
+// VI: Cấu hình menu sidebar theo ngành hàng (Café, Nhà hàng, Karaoke, Spa).
+
+namespace WebClientTpos.Client.Services;
+
+///
+/// EN: Static config for shop-level sidebar menus per vertical type.
+/// VI: Cấu hình tĩnh cho menu sidebar cấp cửa hàng theo loại ngành hàng.
+///
+public static class ShopSidebarConfig
+{
+ public record MenuItem(string Label, string Icon, string Route, bool IsSub = false);
+
+ ///
+ /// EN: Get sidebar menu items for a specific shop vertical.
+ /// VI: Lấy danh sách menu sidebar cho ngành hàng cụ thể.
+ ///
+ public static List