using LiteCharms.Features.S3.Abstractions; using Microsoft.AspNetCore.Components.Forms; using System.ComponentModel.DataAnnotations; using static LiteCharms.Features.S3.Constants; namespace ShopAdmin.Components; public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Service s3Service) { private readonly CancellationTokenSource cancellationTokenSource = new(); private CancellationToken cancellationToken; protected string? ActivePreviewUrl { get; set; } protected CreateProductModel ProductModel { get; set; } = new(); private const long MaxAllowedFileSize = 1024 * 1024 * 5; protected override void OnInitialized() { base.OnInitialized(); cancellationToken = cancellationTokenSource.Token; if (ProductModel.Thumbnails.Count == 0) ProductModel.Thumbnails = [.. Enumerable.Repeat(string.Empty, 5)]; } // Your saving logic goes here when the ledger button is clicked public Task HandleValidSubmit() => Task.CompletedTask; // Checks if a valid URL asset exists at the specified position public bool HasAssetAt(int index) => ProductModel?.Thumbnails == null || index >= ProductModel.Thumbnails.Count ? false : !string.IsNullOrWhiteSpace(ProductModel.Thumbnails[index]); // Handles uploading the primary image node private async Task HandleMainImageUpload(InputFileChangeEventArgs e) { try { var file = e.File; if (file == null) return; using var stream = new MemoryStream(); await file.OpenReadStream(MaxAllowedFileSize).CopyToAsync(stream, cancellationToken); var result = await s3Service.UploadFileAsync(file.Name,stream, MimeTypes.GetMimeType(file.Name), cancellationToken); if (result.IsSuccess) { ProductModel.ImageUrl = result.Value; StateHasChanged(); } } catch (Exception ex) { Console.WriteLine($"Main Image Upload Exception: {ex.Message}"); } } public void SetPreviewActive(string? url) { if (!string.IsNullOrWhiteSpace(url)) { ActivePreviewUrl = url; StateHasChanged(); } } public void ClosePreviewDrawer() { ActivePreviewUrl = null; StateHasChanged(); } // Handles uploading a thumbnail image into its specific slot index private async Task HandleThumbnailUpload(InputFileChangeEventArgs e, int index) { try { var file = e.File; if (file == null) return; using var stream = new MemoryStream(); await file.OpenReadStream(MaxAllowedFileSize, cancellationToken).CopyToAsync(stream, cancellationToken); var result = await s3Service.UploadFileAsync(file.Name, stream, MimeTypes.GetMimeType(file.Name), cancellationToken); if (result.IsSuccess && index < ProductModel.Thumbnails.Count) { ProductModel.Thumbnails[index] = result.Value; StateHasChanged(); } } catch (Exception ex) { Console.WriteLine($"Thumbnail Slot {index} Upload Exception: {ex.Message}"); } } public void ClearMainImage() { if (ActivePreviewUrl == ProductModel.ImageUrl) { ActivePreviewUrl = null; } ProductModel.ImageUrl = null; } public void RemoveThumbnailAt(int index) { if (index >= 0 && index < ProductModel.Thumbnails.Count) { if (ActivePreviewUrl == ProductModel.Thumbnails[index]) { ActivePreviewUrl = null; } ProductModel.Thumbnails[index] = string.Empty; } } } public class CreateProductModel { [Required(ErrorMessage = "Product name is required.")] public string? Name { get; set; } [Required(ErrorMessage = "Summary is required.")] public string? Summary { get; set; } [Required(ErrorMessage = "Description is required.")] public string? Description { get; set; } [Range(0.01, double.MaxValue, ErrorMessage = "Price must be greater than zero.")] public decimal Price { get; set; } [Required(ErrorMessage = "Primary image is required.")] public string? ImageUrl { get; set; } public List Thumbnails { get; set; } = []; }