several customers have complained about the problems they encounter when customizing the CustomerNavigation.cshtml. The main complaints are:
1. Each item is on its own, meaning that if you want to change something in all of them, you need to do it MANUALLY 10 times.
2. If you want to change many things, it becomes really tedious and the chance for mistake making is quite high
3. Creating another custom navigation out of the default one i.e. for mobile only, suffers even more from the same issues
4. From a development standpoint, it is better to remove the code duplication for readability and performance purposes.
I've tried a couple of things and the example I ended up with is this:
- This is the markup:
@model List<CustomerNavigationItemModel>
@using Nop.Web.Models.Customer;
<div class="block block-account-navigation">
<div class="title">
<strong>@T("Account.Navigation")</strong>
</div>
<div class="listbox">
@Html.Widget("account_navigation_before")
<ul class="list">
@foreach (var navigationItem in Model)
{
<li class="list-item @navigationItem.ItemClass">
<a href="@navigationItem.Url" class="@navigationItem.StateClass">@navigationItem.LinkText</a>
</li>
}
</ul>
@Html.Widget("account_navigation_after")
</div>
</div>
- These are the models:
//New models
public class CustomerNavigationItemModel
{
public string Url { get; set; }
public string StateClass { get; set; }
public string LinkText { get; set; }
public string ItemClass { get; set; }
}
public class NavigationItemCharacteristics
{
public CustomerNavigationEnum Tab { get; set; }
public string RouteUrl { get; set; }
public string ResourceName { get; set; }
public string ItemClass { get; set; }
public bool ShouldBeBuild { get; set; }
}
- This is the controller:
[ChildActionOnly]
public ActionResult CustomerNavigation(int selectedTabId = 0)
{
bool buildAvatar = !_customerSettings.AllowCustomersToUploadAvatars;
bool buildRewardPoints = !_rewardPointsSettings.Enabled;
bool buildForumSubscriptions = !_forumSettings.ForumsEnabled || !_forumSettings.AllowCustomersToManageSubscriptions;
bool buildReturnRequests = !_orderSettings.ReturnRequestsEnabled ||
_returnRequestService.SearchReturnRequests(_storeContext.CurrentStore.Id, _workContext.CurrentCustomer.Id, 0, null, 0, 1).Count == 0;
bool buildDownloadableProducts = _customerSettings.HideDownloadableProductsTab;
bool buildBackInStockSubscriptions = _customerSettings.HideBackInStockSubscriptionsTab;
// Think about adding a display order for each item and prode the control to change it from the administration.
var items = new List<NavigationItemCharacteristics>()
{
new NavigationItemCharacteristics()
{
ItemClass = "info",
ResourceName = "Account.CustomerInfo",
RouteUrl = "CustomerInfo",
Tab = CustomerNavigationEnum.Info,
ShouldBeBuild = true
},
new NavigationItemCharacteristics()
{
ItemClass = "addresses",
ResourceName = "Account.CustomerAddresses",
RouteUrl = "CustomerAddresses",
Tab = CustomerNavigationEnum.Addresses,
ShouldBeBuild = true
},
new NavigationItemCharacteristics()
{
ItemClass = "orders",
ResourceName = "Account.CustomerOrders",
RouteUrl = "CustomerOrders",
Tab = CustomerNavigationEnum.Orders,
ShouldBeBuild = true
},
new NavigationItemCharacteristics()
{
ItemClass = "return-request",
ResourceName = "Account.CustomerReturnRequests",
RouteUrl = "CustomerReturnRequests",
Tab = CustomerNavigationEnum.ReturnRequests,
ShouldBeBuild = buildReturnRequests
},
new NavigationItemCharacteristics()
{
ItemClass = "downloadable",
ResourceName = "Account.DownloadableProducts",
RouteUrl = "CustomerDownloadableProducts",
Tab = CustomerNavigationEnum.DownloadableProducts,
ShouldBeBuild = buildDownloadableProducts
},
new NavigationItemCharacteristics()
{
ItemClass = "back-in-stock",
ResourceName = "Account.BackInStockSubscriptions",
RouteUrl = "CustomerBackInStockSubscriptions",
Tab = CustomerNavigationEnum.BackInStockSubscriptions,
ShouldBeBuild = buildBackInStockSubscriptions
},
new NavigationItemCharacteristics()
{
ItemClass = "reward",
ResourceName = "Account.RewardPoints",
RouteUrl = "CustomerRewardPoints",
Tab = CustomerNavigationEnum.RewardPoints,
ShouldBeBuild = buildRewardPoints
},
new NavigationItemCharacteristics()
{
ItemClass = "change-password",
ResourceName = "Account.ChangePassword",
RouteUrl = "CustomerChangePassword",
Tab = CustomerNavigationEnum.ChangePassword,
ShouldBeBuild = true
},
new NavigationItemCharacteristics()
{
ItemClass = "avatar",
ResourceName = "Account.Avatar",
RouteUrl = "CustomerAvatar",
Tab = CustomerNavigationEnum.Avatar,
ShouldBeBuild = buildAvatar
},
new NavigationItemCharacteristics()
{
ItemClass = "forum-subs",
ResourceName = "Account.ForumSubscriptions",
RouteUrl = "CustomerForumSubscriptions",
Tab = CustomerNavigationEnum.ForumSubscriptions,
ShouldBeBuild = buildForumSubscriptions
}
};
var customerNavigationItems = new List<CustomerNavigationItemModel>();
foreach (var item in items)
{
if (item.ShouldBeBuild)
{
customerNavigationItems.Add(BuildCustomerNavigationItem(selectedTabId, item));
}
}
return PartialView(customerNavigationItems);
}
[NonAction]
private CustomerNavigationItemModel BuildCustomerNavigationItem(int selectedTabId, NavigationItemCharacteristics characteristics)
{
string stateClass = selectedTabId == (int)characteristics.Tab ? "active" : "inactive";
var customerNavigationItem = new CustomerNavigationItemModel()
{
Url = Url.RouteUrl(characteristics.RouteUrl),
StateClass = stateClass,
ItemClass = characteristics.ItemClass,
LinkText = _localizationService.GetResource(characteristics.ResourceName)
};
return customerNavigationItem;
}
I also want to mention that these four variables in the CustomerNavigationModel - HideInfo, HideAddresses, HideOrders and HideChangePassword, are always false as by default and never change, so they are irrelevant and unnecessary to exist in the current model.
I hope you'd consider adding this to the new version of nopCommerce, since it would be a very good addition, making the code cleaner and easier to customize!
Kind regards,
Aleks