@page "/manage-product/{id?}" @layout AdminLayout @using Generic @using Commerce.Contracts.DTOs @inject ProductAPIConsumer productAPIConsumer @inject CategoryAPIConsumer categoryAPIConsumer @inject ISnackbar Snackbar

@(string.IsNullOrEmpty(Id) ? "Add New Product" : "Edit Product")

@foreach (var lang in _languages) { }

Product Settings

Enable to compose from other products

Product Name
@(_languages[_activeLang])

Description
@(_languages[_activeLang])

Product Specifications
@(_languages[_activeLang])

@if (!_technicalDetails.ContainsKey(_activeLang) || !_technicalDetails[_activeLang].Any()) {

No specifications for @(_languages[_activeLang])

} else { @foreach (var item in _technicalDetails[_activeLang]) {
} }

Product Media

@if (product.IsBundle) {

Bundle Composition

Included Products (@(product.ChildProducts?.Count ?? 0))

@if (product.ChildProducts == null || !product.ChildProducts.Any()) {
No products added. Search and add below.
} else {
@foreach (var item in product.ChildProducts) {
@if (item.Photos?.Any() == true) { }
@item.Translations?.FirstOrDefault()?.Info?.Name ?? string.Empty) @item.Price?.ToString("C")
}
}

Find & Add Products

@if (_isSearching) { } else { }
@if (_searchResults != null && _searchResults.Any()) {
@foreach (var res in _searchResults) {
@if (res.Photos?.Any() == true) { }
@res.Translations?.FirstOrDefault()?.Info?.Name ?? string.Empty) @res.Price?.ToString("C")
}
}
}
@code { [Parameter] public string? Id { get; set; } ProductVM product = new(); private EditContext? _editContext; Media? mediaComponent; // Search state ProductFilter searchFilter = new() { IsBundle = false }; Dictionary _names = new(); Dictionary _descriptions = new(); Dictionary> _technicalDetails = new(); List _searchResults = new(); bool _isSearching = false; private string _activeLang = "en"; private readonly Dictionary _languages = new() { { "en", "English" }, { "ar", "العربية" }, { "es", "Español" }, { "de", "Deutsch" } }; protected override async Task OnInitializedAsync() { if (!string.IsNullOrEmpty(Id)) { product = await productAPIConsumer.GetProduct(Id); } // Map from Translations to local dictionaries foreach (var t in product.Translations ?? new()) { _names[t.Language] = t.Info.Name; _descriptions[t.Language] = t.Info.Description; _technicalDetails[t.Language] = t.Info.TechnicalDetails?.ToList() ?? new(); } // Ensure supported cultures exist in dictionaries foreach (var lang in _languages.Keys) { if (!_names.ContainsKey(lang)) _names[lang] = ""; if (!_descriptions.ContainsKey(lang)) _descriptions[lang] = ""; if (!_technicalDetails.ContainsKey(lang)) _technicalDetails[lang] = new(); } product.Photos ??= Array.Empty(); product.ChildProducts ??= new List(); SyncTranslations(); _editContext = new EditContext(product); } void SyncTranslations() { product.Translations = _languages.Keys.Select(lang => new ProductTranslationVM { Language = lang, Info = new ProductInfoVM { Name = _names.GetValueOrDefault(lang, ""), Description = _descriptions.GetValueOrDefault(lang, ""), TechnicalDetails = _technicalDetails.GetValueOrDefault(lang, new()) } }).ToList(); } async Task HandleSubmit() { SyncTranslations(); if (_editContext != null && _editContext.Validate()) { await OnSubmit(); } } void AddTechnicalDetail() { if (!_technicalDetails.ContainsKey(_activeLang)) { _technicalDetails[_activeLang] = new List(); } _technicalDetails[_activeLang].Add(new TechnicalDetailVM()); } void RemoveTechnicalDetail(TechnicalDetailVM item) { if (_technicalDetails.ContainsKey(_activeLang)) { _technicalDetails[_activeLang].Remove(item); } } async Task HandleSearchKeyUp() { await SearchProducts(); } async Task SearchProducts() { if (string.IsNullOrWhiteSpace(searchFilter.Name) && !searchFilter.CategoryId.HasValue) { _searchResults.Clear(); return; } _isSearching = true; try { var (results, _) = await productAPIConsumer.FetchProduct(searchFilter, new Pagination { PageSize = 10, CurrentPage = 1 }); // Filter out the current product itself to avoid circular bundles if it already exists _searchResults = results.Where(x => x.Id != product.Id).ToList(); } finally { _isSearching = false; } } void AddToBundle(ProductVM item) { if (product.ChildProducts == null) product.ChildProducts = new List(); if (!product.ChildProducts.Any(x => x.Id == item.Id)) { product.ChildProducts.Add(item); _searchResults.Clear(); searchFilter.Name = ""; } } void RemoveFromBundle(ProductVM item) { if (product.ChildProducts != null) { product.ChildProducts.Remove(item); } } async Task OnSubmit() { Console.WriteLine("OnSubmit started"); try { if (mediaComponent != null) { Console.WriteLine("Starting ProcessUploadsAsync"); var uploadResult = await mediaComponent.ProcessUploadsAsync(); Console.WriteLine("ProcessUploadsAsync finished successfully"); product.Photos = uploadResult.FinalUrls.ToArray(); } SyncTranslations(); if (string.IsNullOrEmpty(Id)) { Console.WriteLine("Creating product..."); await productAPIConsumer.CreateProduct(product); Snackbar.Add("Product added successfully!", Severity.Success); ResetForm(); } else { Console.WriteLine("Updating product..."); await productAPIConsumer.UpdateProduct(product); Snackbar.Add("Product updated successfully!", Severity.Success); } } catch (Exception ex) { Console.WriteLine($"Caught exception in OnSubmit: {ex.Message}"); Snackbar.Add($"Error: {ex.Message}", Severity.Error); } } void ResetForm() { product = new(); _names.Clear(); _descriptions.Clear(); _technicalDetails.Clear(); foreach (var lang in _languages.Keys) { _names[lang] = ""; _descriptions[lang] = ""; _technicalDetails[lang] = new(); } SyncTranslations(); _editContext = new EditContext(product); if (mediaComponent != null) { mediaComponent.Clear(); } } }