diff --git a/CulinaryCommandApp/Components/Layout/NavMenu.razor b/CulinaryCommandApp/Components/Layout/NavMenu.razor index cb3896c..399dd38 100644 --- a/CulinaryCommandApp/Components/Layout/NavMenu.razor +++ b/CulinaryCommandApp/Components/Layout/NavMenu.razor @@ -67,6 +67,11 @@ Manage Users + } else if (_role == "Manager") { diff --git a/CulinaryCommandApp/Components/Pages/MarginEdge.razor b/CulinaryCommandApp/Components/Pages/MarginEdge.razor new file mode 100644 index 0000000..6c87348 --- /dev/null +++ b/CulinaryCommandApp/Components/Pages/MarginEdge.razor @@ -0,0 +1,250 @@ +@page "/margin-edge" +@using CulinaryCommand.Services +@using CulinaryCommand.Services.UserContextSpace +@using System.Web @* For HttpUtility if needed, but simple string building works too *@ +@using System.Text.Json + +@inject IUserContextService UserCtx +@inject HttpClient Http + +
+

MarginEdge API Tester

+
+ +
+
+ + +
+
+ +
+
+ + +
+ + @if (requiresLocationId) { +
+ + +
+ } + + @if (requiresId) + { +
+ + +
+ } +
+ + @if (currentPath == "/orders") + { +
+
+ + +
+
+ + +
+
+ } + +
+
+ +
+
+ + @* @if (!string.IsNullOrEmpty(apiResponse)) + { +
+
Response Result:
+
@apiResponse
+
+ } *@ + @if (!string.IsNullOrEmpty(apiResponse)) +{ +
+
+
Results:
+
+ + +
+
+ + @if (viewMode == "json") + { +
@apiResponse
+ } + else + { +
+ @try + { + var doc = JsonDocument.Parse(apiResponse); + // MarginEdge often returns an array at the root or inside a "content" property + + IEnumerable items; + if (doc.RootElement.ValueKind == JsonValueKind.Array) + { + items = doc.RootElement.EnumerateArray(); + } + else + { + // Find the first array property at the root — handles "restaurants", "content", "orders", etc. + var arrayProp = doc.RootElement.EnumerateObject() + .FirstOrDefault(p => p.Value.ValueKind == JsonValueKind.Array); + items = arrayProp.Value.ValueKind == JsonValueKind.Array + ? arrayProp.Value.EnumerateArray() + : Enumerable.Empty(); + } + + @foreach (var item in items) + { +
+
+
+ @*
@GetSafeString(item, "id")
+
@GetSafeString(item, "name", "orderNumber")
+
*@ +
+
+ @foreach (var prop in item.EnumerateObject().Take(8)) + { + var valStr = prop.Value.ValueKind == JsonValueKind.Object || prop.Value.ValueKind == JsonValueKind.Array + ? $"[{prop.Value.ValueKind}]" + : prop.Value.ToString(); +
+ @prop.Name: + @valStr +
+ } +
+
+
+
+
+ } + } + catch + { +
Could not parse response into cards. It might not be a list.
+ } +
+ } +
+} +
+ +@code { + private string apiKey = ""; + private string apiResponse = ""; + private string resourceId = ""; + private string locationId = ""; + private string currentPath = "/restaurantUnits"; + + private DateTime startDate = DateTime.Today.AddDays(-7); + private DateTime endDate = DateTime.Today; + + private bool requiresLocationId => + new[] { "orders", "products", "categories", "vendors" } + .Any(keyword => currentPath.Contains(keyword, StringComparison.OrdinalIgnoreCase)); + + private bool requiresId => currentPath.Contains(":"); + + private List Endpoints = new() + { + new("Get available restaurants", "/restaurantUnits", "GET"), + new("Get group categories", "/restaurantUnits/groupCategories", "GET"), + new("Get unit groups", "/restaurantUnits/groups", "GET"), + new("Get orders", "/orders", "GET"), + new("Get order detail", "/orders/:orderId", "GET"), + new("Get products", "/products", "GET"), + new("Get categories", "/categories", "GET"), + new("Get vendors", "/vendors", "GET"), + new("Get vendor items", "/vendors/:vendorId/vendorItems", "GET") + }; + + private void OnEndpointChanged(ChangeEventArgs e) + { + currentPath = e.Value?.ToString() ?? ""; + apiResponse = ""; + } + + private async Task ExecuteQuery() + { + try + { + apiResponse = "Loading..."; + + // Build URL + var path = currentPath; + + // Swap :orderId / :vendorId placeholders + if (requiresId && !string.IsNullOrEmpty(resourceId)) + path = System.Text.RegularExpressions.Regex.Replace(path, @":[^/]+", resourceId); + + var baseUrl = $"https://api.marginedge.com/public{path}"; + var query = new System.Collections.Generic.List(); + + if (requiresLocationId && !string.IsNullOrEmpty(locationId)) + query.Add($"restaurantUnitId={locationId}"); + + if (currentPath == "/orders") + { + query.Add($"startDate={startDate:yyyy-MM-dd}"); + query.Add($"endDate={endDate:yyyy-MM-dd}"); + } + + var finalUrl = query.Count > 0 ? $"{baseUrl}?{string.Join("&", query)}" : baseUrl; + + var request = new HttpRequestMessage(HttpMethod.Get, finalUrl); + request.Headers.Add("X-API-KEY", apiKey); + + var response = await Http.SendAsync(request); + var content = await response.Content.ReadAsStringAsync(); + + try + { + var jsonElement = JsonSerializer.Deserialize(content); + apiResponse = JsonSerializer.Serialize(jsonElement, new JsonSerializerOptions + { + WriteIndented = true + }); + } + catch + { + apiResponse = content; + } + } + catch (Exception ex) + { + apiResponse = $"Error: {ex.Message}"; + } + } + + public record EndpointInfo(string Name, string Path, string Method); + + private string viewMode = "json"; // Default view + + // Helper to try multiple property names (like 'name' or 'orderNumber') + private string GetSafeString(System.Text.Json.JsonElement el, params string[] propertyNames) + { + foreach (var name in propertyNames) + { + if (el.TryGetProperty(name, out System.Text.Json.JsonElement prop)) return prop.ToString(); + } + return "N/A"; + } +} \ No newline at end of file