Files
shopadmin/ShopAdmin/Components/CreateProduct.razor.cs
T
Khwezi Mngoma 0d3bd52581
continuous-integration/drone/pr Build is passing
Moved CreateProductModel to shared Features library
2026-05-20 21:18:41 +02:00

188 lines
5.9 KiB
C#

using LiteCharms.Features.S3.Abstractions;
using LiteCharms.Features.Shop.Products.Models;
using static LiteCharms.Features.S3.Constants;
namespace ShopAdmin.Components;
public partial class CreateProduct([FromKeyedServices(BookshopBucketName)] IS3Service s3Service)
{
private bool isCalendarOpen = false;
private DateTime calendarViewingMonth = DateTime.Today;
private List<DateTime?> calendarDays = new();
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;
private readonly Func<string, string> GetFileKeyFromUrl = url => url.Split('/').Last();
protected override void OnInitialized()
{
base.OnInitialized();
cancellationToken = cancellationTokenSource.Token;
if (ProductModel.Thumbnails.Count == 0)
ProductModel.Thumbnails = [.. Enumerable.Repeat(string.Empty, 5)];
}
public Task HandleValidSubmit() => Task.CompletedTask;
public bool HasAssetAt(int index) => (ProductModel?.Thumbnails) != null && index < ProductModel.Thumbnails.Count &&
!string.IsNullOrWhiteSpace(ProductModel.Thumbnails[index]);
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);
stream.Seek(0, SeekOrigin.Begin);
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)) return;
ActivePreviewUrl = url;
StateHasChanged();
}
public void ClosePreviewDrawer()
{
ActivePreviewUrl = null;
StateHasChanged();
}
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);
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)
{
ProductModel.Thumbnails[index] = result.Value;
StateHasChanged();
}
}
catch (Exception ex)
{
Console.WriteLine($"Thumbnail Slot {index} Upload Exception: {ex.Message}");
}
}
public async Task ClearMainImage()
{
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 async Task RemoveThumbnailAt(int index)
{
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}");
}
private void ToggleCalendar()
{
if (!isCalendarOpen)
{
// Default viewport context to currently selected value or fallback to today
calendarViewingMonth = ProductModel.PublishDate;
RebuildCalendarMatrix();
}
isCalendarOpen = !isCalendarOpen;
}
private void RebuildCalendarMatrix()
{
calendarDays.Clear();
var firstDayOfMonth = new DateTime(calendarViewingMonth.Year, calendarViewingMonth.Month, 1);
var totalDaysInMonth = DateTime.DaysInMonth(calendarViewingMonth.Year, calendarViewingMonth.Month);
// Offset leading days to align day positions correctly with day of week headers
int leadingOffsets = (int)firstDayOfMonth.DayOfWeek;
for (int i = 0; i < leadingOffsets; i++)
{
calendarDays.Add(null);
}
// Populate active dates
for (int day = 1; day <= totalDaysInMonth; day++)
{
calendarDays.Add(new DateTime(calendarViewingMonth.Year, calendarViewingMonth.Month, day));
}
}
private void NavigateToPreviousMonth()
{
calendarViewingMonth = calendarViewingMonth.AddMonths(-1);
RebuildCalendarMatrix();
}
private void NavigateToNextMonth()
{
calendarViewingMonth = calendarViewingMonth.AddMonths(1);
RebuildCalendarMatrix();
}
private void SelectCalendarDate(DateTime date)
{
ProductModel.PublishDate = date;
isCalendarOpen = false; // Collapse popup smoothly on successful selection
StateHasChanged();
}
}