In Part 19, we are taking our Food Ordering System to a professional level by adding Dynamic Search Logic. This update to the
MyOrders method allows users to filter through hundreds of orders by status, specific dates, or price, ensuring a high-performance experience.Step-by-Step Logic Explanation
Status Filtering: We check if a status is selected. If it isn't "All", we use
.Where()to narrow down the results. We also store the selection inViewBag.CurrentStatusso the dropdown "remembers" what the user picked.Date Range Logic:
From Date: Filters orders that occurred on or after the selected date.
To Date: We use
.AddDays(1)here. This is a pro-tip! SinceDateTimeincludes time (00:00:00), adding one day ensures we include all orders placed during the final day of the range.
The Switch Expression (Sorting): This is a modern C# feature. It concisely handles multiple sorting scenarios:
Newest First (Default): Ensures users see their most recent meal at the top.
Price Sorting: Allows users to find their most expensive or cheapest orders easily.
ViewBag.StatusList: We provide a hardcoded list of statuses to the View to populate the dropdown menu dynamically.
public IActionResult MyOrders(string status, string sortOrder, DateTime? fromDate, DateTime? toDate)
{
// ... (Retrieve UserId and initial Order query from Part 18)
// Filter by Status
if (!string.IsNullOrEmpty(status) && status != "All")
{
orders = orders.Where(o => o.Status == status);
ViewBag.CurrentStatus = status;
}
// Filter by Date Range
if (fromDate.HasValue)
{
orders = orders.Where(o => o.OrderDate >= fromDate.Value);
ViewBag.FromDate = fromDate.Value.ToString("yyyy-MM-dd");
}
if (toDate.HasValue)
{
// Add 1 day to include the entire 'To' date
orders = orders.Where(o => o.OrderDate <= toDate.Value.AddDays(1));
ViewBag.ToDate = toDate.Value.ToString("yyyy-MM-dd");
}
// Sorting Logic
ViewBag.CurrentSort = sortOrder;
orders = sortOrder switch
{
"date_asc" => orders.OrderBy(o => o.OrderDate),
"total_desc" => orders.OrderByDescending(o => o.TotalAmount),
"total_asc" => orders.OrderBy(o => o.TotalAmount),
_ => orders.OrderByDescending(o => o.OrderDate) // default: newest first
};
ViewBag.StatusList = new List<string> { "All", "Pending", "Confirmed", "Preparing", "OutForDelivery", "Delivered", "Cancelled" };
return View(orders.ToList());
}
We need to provide the user interface for our new filtering logic. This HTML snippet creates a responsive Search & Filter Bar that sits at the top of the "My Orders" page, allowing customers to interact with the backend code we wrote in the previous step.
Step-by-Step Code Explanation
method="get": This is vital for search forms. It puts the search parameters (like status and dates) directly into the URL. This allows users to refresh the page or bookmark a specific search result.asp-action="MyOrders": This Tag Helper ensures the form submits specifically to ourMyOrdersmethod in the Controller.Sticky Data (ViewBag): Notice
value="@ViewBag.FromDate"and theSelectList. This ensures that after the user clicks "Filter," their selected dates and status stay in the boxes so they don't have to re-type them.Bootstrap Grid (
col-md-x): We use a mix of column sizes (3, 2, 2, 3, 2) to ensure the bar looks balanced and professional on widescreen monitors while stacking vertically on mobile.align-items-end: This utility class keeps the "Filter" button perfectly aligned with the bottom of the input boxes, even though those boxes have labels above them.
@if (TempData["Success"] != null)
{
<div class="alert alert-success alert-dismissible fade show" role="alert">
@TempData["Success"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
<!-- Filter Section -->
<div class="card shadow-sm mb-4">
<div class="card-body bg-light">
<form method="get" asp-action="MyOrders" class="row g-3 align-items-end">
<div class="col-md-3">
<label class="form-label">Status</label>
<select name="status" class="form-select" asp-items="@(new SelectList(ViewBag.StatusList, ViewBag.CurrentStatus))">
<option value="All">All Status</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">From Date</label>
<input type="date" name="fromDate" class="form-control" value="@ViewBag.FromDate" />
</div>
<div class="col-md-2">
<label class="form-label">To Date</label>
<input type="date" name="toDate" class="form-control" value="@ViewBag.ToDate" />
</div>
<div class="col-md-3">
<label class="form-label">Sort By</label>
<select name="sortOrder" class="form-select">
<option value="">Newest First</option>
<option value="date_asc" selected="@(ViewBag.CurrentSort == "date_asc")">Oldest First</option>
<option value="total_desc" selected="@(ViewBag.CurrentSort == "total_desc")">Highest Amount</option>
<option value="total_asc" selected="@(ViewBag.CurrentSort == "total_asc")">Lowest Amount</option>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-funnel"></i> Filter
</button>
</div>
</form>
@if (!string.IsNullOrEmpty(ViewBag.CurrentStatus) || ViewBag.FromDate != null || ViewBag.ToDate != null)
{
<div class="mt-2">
<a href="/Order/MyOrders" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-x-circle"></i> Clear Filters
</a>
</div>
}
</div>
</div>
Comments
Post a Comment