I'm new to development (I'm self Taught I got a job recently as an"app Developer") and this is my first real big project. In essence, it's an e-commerce store that uses a very awkward API. My Checkout process is taking 6 seconds per item and you can imagine if I let a user checkout 50+ items, they will think something's wrong.
I'm going to share my whole checkout process along with a question. What are my bottlenecks? Too many loops to make checks? How do I improve something like this?
A few things to note, I have a variable and a single Product. Sometimes the API returns the Stock Quantity of null
, which just means that it's unlimited.
private async void Checkout_clicked(object sender, EventArgs e)
{
try
{
await Navigation.PushPopupAsync(new LoadingPopup());
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
try
{
if (FullCart.CartList == null || FullCart.CartList.Count <= 0 || !FullCart.CartList.Any())
{
var yx = await DisplayAlert("Whoops",
"Cart seem's to be empty, We cant checkout nothing", "Back to Cart", "Supplier");
if (yx)
{
}
else
{
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Suppliers());
Application.Current.MainPage = masterDetailPage;
}
}
else
{
await BeginCheckout();
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
}
private async Task BeginCheckout()
{
try
{
//You cant checkout if your not logged in There are no Guest Checkouts(I can But would rather not)
if (Users.LoggedIn && _spamClick == false)
{
if (_orderlineitems == null) _orderlineitems = new List<OrderLineItem>();
RestAPI rest = new RestAPI("http://xxxxx/wp-json/wc/v2/",
"xxxxxxxxxxxxxxxxxxxxxxxxx", "cs_xxxxxxxxxxxxxxxxxxxxxxxx");
var wc = new WCObject(rest);
await IsInStock();
var order = new Order { status = "on-hold", customer_id = Users.CId };
foreach (var item in _simpleCartlist)
if (_simpleCartlist.Any(i => i.InStock == false))
{
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
}
else if (_simpleCartlist.All(i => i.InStock))
{
if (item.StockStatus == "instock" || item.StockStatus is string stringValue && string.IsNullOrWhiteSpace(stringValue) || item.StockStatus == null)
{
var a = Convert.ToInt32(item.ProductQuantity);
if (item.VariationId <= 0) item.VariationId = item.PId;
if (item.StockQuantity == 0)
{
_productBoughtOut = true;
_productnames.Add(item.ProductName);
}
order.line_items = order.line_items ?? new List<OrderLineItem>();
order.line_items.Add(new OrderLineItem
{ product_id = item.PId, variation_id = item.VariationId, quantity = a });
}
else
{
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
var yx = await DisplayAlert("Order Cant be Placed",
$"{item.ProductName} is out of stock",
"Back to Cart", "Home");
if (yx)
{
}
else
{
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Home());
Application.Current.MainPage = masterDetailPage;
}
}
}
if (_productBoughtOut)
{
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
var yx = await DisplayAlert("Order Cant be Placed", $"Not enough stock for {_productnames}",
"Back to Cart", "Home");
if (yx)
{
}
else
{
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Home());
Application.Current.MainPage = masterDetailPage;
}
}
else if (_simpleCartlist.All(i => i.InStock))
{
if (FullCart.CartList != null && _spamClick == false || _items.Items != null && _spamClick == false)
{
_spamClick = true;
await wc.Order.Add(order);
Preferences.Clear("Cart");
Preferences.Remove("Cart");
FullCart.CartList.Clear();
_items.Items.Clear();
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Checkedout());
Application.Current.MainPage = masterDetailPage;
}
_spamClick = true;
}
}
else
{
if (_spamClick)
{
await DisplayAlert("Woops", "Your trying to order twice", "Ok");
}
else
{
var y = await DisplayAlert("Woops", "Please Login to check Out", "Login", "Home");
if (y)
{
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Login());
Application.Current.MainPage = masterDetailPage;
}
else
{
await Navigation.PushAsync(new Home());
}
}
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
}
private async Task SingleCheck()
{
try
{
foreach (var CartItem in _simpleCartlist)
if (_currentListItem == CartItem.PId)
{
if (_singleProduct.stock_quantity == null)
{
//CartItem.InStock = true;
_singleProduct.stock_quantity = 999999;
}
if (CartItem.ProductQuantity == 0)
{
CartItem.ErrorMsg = "Item requires a Quantity of atleast 1" + System.Environment.NewLine + "Quantity Cannot be 0!";
await DisplayAlert("Oops", "Whe can't checkout nothing See if a products quantity isnt 0", "Ok");
return;
}
if (_singleProduct.stock_quantity == 0 || _singleProduct.stock_status == "outofstock" ||
CartItem.ProductQuantity > _singleProduct.stock_quantity)
{
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
CartItem.InStock = false;
var AlertResult = await DisplayAlert("Not Enough Products",
$"There is this much Stock left: {_singleProduct.stock_quantity} for {_singleProduct.name}",
"Back to Cart", "Keep Shopping");
CartItem.ErrorMsg = "Product shortage " + $" There is this much Stock left: {_singleProduct.stock_quantity} for {_singleProduct.name}";
if (AlertResult)
{
CartItem.InStock = false;
CartItem.StockQuantity = Convert.ToInt32(_singleProduct.stock_quantity);
_items = new ItemList(FullCart.CartList);
cartView.BeginRefresh();
CartItem.StockStatus = _singleProduct.stock_status;
cartView.EndRefresh();
return;
}
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Home());
Application.Current.MainPage = masterDetailPage;
}
else if (_singleProduct.stock_quantity != 0 && _singleProduct.stock_status == "instock" &&
CartItem.ProductQuantity <= _singleProduct.stock_quantity)
{
CartItem.ErrorMsg = "";
CartItem.InStock = true;
}
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
}
private async Task VariableCheck()
{
//TODO if your seeing this, Your probably Developing on this now, if you're... Run! Honestly Run...
try
{
foreach (var CartItem in _simpleCartlist)
if (_currentListItem == CartItem.PId)
{
if (_varProduct.stock_quantity == null)
{
_varProduct.stock_quantity = 999999;
}
if (CartItem.ProductQuantity == 0)
{
CartItem.ErrorMsg = "Item requires a Quantity of atleast 1" + System.Environment.NewLine + "Quantity Cannot be 0!";
await DisplayAlert("Oops", "Whe can't checkout nothing See if a products quantity isnt 0", "Ok");
return;
}
if (_varProduct.stock_quantity == 0 || _varProduct.stock_status == "outofstock" ||
CartItem.ProductQuantity > _varProduct.stock_quantity)
{
try
{
await Navigation.PopPopupAsync();
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
CartItem.InStock = false;
var AlertResult = await DisplayAlert("Not Enough Products",
$"There is this much Stock left: {_varProduct.stock_quantity} for {CartItem.ProductName} {_varProduct.attributes[2].option}",
"Back to Cart", "Keep Shopping");
CartItem.ErrorMsg = "Not Enough Products" + $"There is this much Stock left: {_varProduct.stock_quantity} for {CartItem.ProductName} {_varProduct.attributes[2].option}";
if (AlertResult)
{
CartItem.InStock = false;
CartItem.StockQuantity = Convert.ToInt32(_varProduct.stock_quantity);
_items = new ItemList(FullCart.CartList);
cartView.BeginRefresh();
CartItem.StockStatus = _varProduct.stock_status;
cartView.EndRefresh();
return;
}
var masterDetailPage = new Home();
masterDetailPage.Detail = new NavigationPage(new Home());
Application.Current.MainPage = masterDetailPage;
}
else if (_varProduct.stock_quantity != 0 && _varProduct.stock_status == "instock" &&
CartItem.ProductQuantity <= _varProduct.stock_quantity)
{
CartItem.ErrorMsg = "";
CartItem.InStock = true;
}
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
}
private readonly List<CartList> _simpleCartlist;
private int _currentId;
private int _currentListItem;
private ItemList _items;
private List<OrderLineItem> _orderlineitems;
private bool _productBoughtOut;
private List<string> _productnames;
private Product _singleProduct;
private bool _spamClick;
private Variation _varProduct;
private bool _loading;
public bool loading
{
get => _loading;
set
{
if (_loading == value) return;
_loading = value;
RaisePropertyChanged();
}
}
private bool _running;
public bool running
{
get => _running;
set
{
if (_running == value) return;
_running = value;
RaisePropertyChanged();
}
}
The idea with spam-click is to avoid Double orders. I can definitely understand the frustration with all my if's. Any suggestions in regards to that would be appreciated.