From 530b8ffea2f760f82b1a8cdbd94bf8a1f01efc42 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Wed, 20 May 2026 16:12:10 +0200 Subject: [PATCH] Added image deletion functionality to product creation --- ShopAdmin/Components/CreateProduct.razor.cs | 77 +++++++++++++-------- ShopAdmin/ShopAdmin.csproj | 4 +- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/ShopAdmin/Components/CreateProduct.razor.cs b/ShopAdmin/Components/CreateProduct.razor.cs index fa2b9cd..2a531f5 100644 --- a/ShopAdmin/Components/CreateProduct.razor.cs +++ b/ShopAdmin/Components/CreateProduct.razor.cs @@ -1,6 +1,4 @@ using LiteCharms.Features.S3.Abstractions; -using Microsoft.AspNetCore.Components.Forms; -using System.ComponentModel.DataAnnotations; using static LiteCharms.Features.S3.Constants; namespace ShopAdmin.Components; @@ -16,6 +14,8 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se private const long MaxAllowedFileSize = 1024 * 1024 * 5; + private readonly Func GetFileKeyFromUrl = url => url.Split('/').Last(); + protected override void OnInitialized() { base.OnInitialized(); @@ -26,15 +26,11 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se 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]); + public bool HasAssetAt(int index) => (ProductModel?.Thumbnails) != null && index < ProductModel.Thumbnails.Count && + !string.IsNullOrWhiteSpace(ProductModel.Thumbnails[index]); - // Handles uploading the primary image node private async Task HandleMainImageUpload(InputFileChangeEventArgs e) { try @@ -47,7 +43,9 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se await file.OpenReadStream(MaxAllowedFileSize).CopyToAsync(stream, cancellationToken); - var result = await s3Service.UploadFileAsync(file.Name,stream, + stream.Seek(0, SeekOrigin.Begin); + + var result = await s3Service.UploadFileAsync(file.Name, stream, MimeTypes.GetMimeType(file.Name), cancellationToken); if (result.IsSuccess) @@ -65,20 +63,20 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se public void SetPreviewActive(string? url) { - if (!string.IsNullOrWhiteSpace(url)) - { - ActivePreviewUrl = url; - StateHasChanged(); - } + if (string.IsNullOrWhiteSpace(url)) return; + + 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 @@ -91,7 +89,9 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se await file.OpenReadStream(MaxAllowedFileSize, cancellationToken).CopyToAsync(stream, cancellationToken); - var result = await s3Service.UploadFileAsync(file.Name, stream, + stream.Seek(0, SeekOrigin.Begin); + + var result = await s3Service.UploadFileAsync(file.Name, stream, MimeTypes.GetMimeType(file.Name), cancellationToken); if (result.IsSuccess && index < ProductModel.Thumbnails.Count) @@ -107,25 +107,42 @@ public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Se } } - public void ClearMainImage() + public async Task ClearMainImage() { - if (ActivePreviewUrl == ProductModel.ImageUrl) - { - ActivePreviewUrl = null; - } + if (string.IsNullOrEmpty(ProductModel.ImageUrl)) return; + + var targetUrl = ProductModel.ImageUrl; + + if (ActivePreviewUrl == targetUrl) ActivePreviewUrl = null; + ProductModel.ImageUrl = null; + + StateHasChanged(); + + var result = await s3Service.DeleteFileAsync(GetFileKeyFromUrl(targetUrl)); + + if (!result.IsSuccess) + Console.WriteLine($"[S3 Orphan Cleanup Failure]: {result.Errors[0].Message}"); } - public void RemoveThumbnailAt(int index) + public async Task RemoveThumbnailAt(int index) { - if (index >= 0 && index < ProductModel.Thumbnails.Count) - { - if (ActivePreviewUrl == ProductModel.Thumbnails[index]) - { - ActivePreviewUrl = null; - } - ProductModel.Thumbnails[index] = string.Empty; - } + if (index < 0 || index >= ProductModel.Thumbnails.Count) return; + + var targetUrl = ProductModel.Thumbnails[index]; + + if (string.IsNullOrEmpty(targetUrl)) return; + + if (ActivePreviewUrl == targetUrl) ActivePreviewUrl = null; + + ProductModel.Thumbnails[index] = string.Empty; + + StateHasChanged(); + + var result = await s3Service.DeleteFileAsync(GetFileKeyFromUrl(targetUrl)); + + if (result.IsFailed) + Console.WriteLine($"[S3 Thumbnail Cleanup Failure]: {result.Errors[0].Message}"); } } diff --git a/ShopAdmin/ShopAdmin.csproj b/ShopAdmin/ShopAdmin.csproj index 1691733..7ec4ff7 100644 --- a/ShopAdmin/ShopAdmin.csproj +++ b/ShopAdmin/ShopAdmin.csproj @@ -16,7 +16,7 @@ - + @@ -59,6 +59,8 @@ + +