Events-MVC (example with htmx)

This commit is contained in:
Boris Milašinović
2026-04-25 22:21:35 +02:00
parent eb04483417
commit 0ee1b22f61
114 changed files with 7966 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace Events.MVC.Models.Countries;
public class CountryTranslationViewModel
{
[Display(Name = "Language")]
[StringLength(10)]
public string LanguageCode { get; set; } = string.Empty;
[Display(Name = "Translation")]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Sieve.Attributes;
namespace Events.MVC.Models.Countries;
public class CountryViewModel
{
[Display(Name = "Code")]
[Required]
[StringLength(3, MinimumLength = 2)]
[Sieve(CanSort = true, CanFilter = true)]
public string Code { get; set; } = string.Empty;
[Display(Name = "Alpha-3")]
[Required]
[StringLength(3, MinimumLength = 3)]
[Sieve(CanSort = true, CanFilter = true)]
public string Alpha3 { get; set; } = string.Empty;
[Display(Name = "Name")]
[Required]
[StringLength(100)]
[Sieve(CanSort = true, CanFilter = true)]
public string Name { get; set; } = string.Empty;
public List<CountryTranslationViewModel> Translations { get; set; } = [];
}

View File

@@ -0,0 +1,8 @@
namespace Events.MVC.Models;
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}

View File

@@ -0,0 +1,26 @@
using System.ComponentModel.DataAnnotations;
using Sieve.Attributes;
namespace Events.MVC.Models.Events;
public class EventViewModel
{
[Display(Name = "ID")]
[Sieve(CanSort = true)]
public int Id { get; set; }
[Display(Name = "Name")]
[Required]
[StringLength(150)]
[Sieve(CanSort = true, CanFilter = true)]
public string Name { get; set; } = string.Empty;
[Display(Name = "Date")]
[DataType(DataType.Date)]
[Sieve(CanSort = true)]
public DateOnly EventDate { get; set; }
[Display(Name = "Participants")]
[Sieve(CanSort = true)]
public int ParticipantsCount { get; set; }
}

View File

@@ -0,0 +1,3 @@
namespace Events.MVC.Models;
public record PagedList<T>(List<T> Data, PagingInfo PagingInfo);

View File

@@ -0,0 +1,39 @@
namespace Events.MVC.Models;
public class PagingInfo
{
public int TotalItemsCount { get; set; }
public int FilteredItemsCount { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public string Sorts { get; set; } = "Name";
public string Filters { get; set; } = string.Empty;
public string NameFilter { get; set; } = string.Empty;
public int TotalPages => Math.Max(1, (int)Math.Ceiling((decimal)FilteredItemsCount / ItemsPerPage));
public bool IsFiltered => !string.IsNullOrWhiteSpace(Filters);
public string ToggleSort(string propertyName)
{
return string.Equals(Sorts, propertyName, StringComparison.OrdinalIgnoreCase)
? $"-{propertyName}"
: propertyName;
}
public bool IsSortedBy(string propertyName)
{
return string.Equals(Sorts.TrimStart('-'), propertyName, StringComparison.OrdinalIgnoreCase);
}
public bool IsDescending()
{
return Sorts.StartsWith("-", StringComparison.Ordinal);
}
}

View File

@@ -0,0 +1,10 @@
namespace Events.MVC.Models;
public class PagingSettings
{
public const string SectionName = "Paging";
public int PageSize { get; set; } = 2;
public int PageOffset { get; set; } = 5;
}

View File

@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Events.MVC.Models.People;
public class PeoplePageViewModel
{
public PagedList<PersonViewModel> People { get; set; } = new([], new PagingInfo());
public List<SelectListItem> CountryOptions { get; set; } = [];
public string CountryFilter { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,100 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;
using Sieve.Attributes;
namespace Events.MVC.Models.People;
public class PersonViewModel : IValidatableObject
{
[Sieve(CanSort = true)]
public int Id { get; set; }
[Display(Name = "First name")]
[StringLength(100)]
public string? FirstName { get; set; }
[Display(Name = "Last name")]
[StringLength(100)]
public string? LastName { get; set; }
[Display(Name = "First name (transcription)")]
[Required]
[StringLength(100)]
[Sieve(CanSort = true)]
public string FirstNameTranscription { get; set; } = string.Empty;
[Display(Name = "Last name (transcription)")]
[Required]
[StringLength(100)]
[Sieve(CanSort = true)]
public string LastNameTranscription { get; set; } = string.Empty;
[Display(Name = "Address")]
[StringLength(200)]
public string? AddressLine { get; set; }
[Display(Name = "Postal code")]
[StringLength(20)]
public string? PostalCode { get; set; }
[Display(Name = "City")]
[StringLength(100)]
public string? City { get; set; }
[Display(Name = "Address country")]
[StringLength(100)]
public string? AddressCountry { get; set; }
[Display(Name = "E-mail")]
[EmailAddress]
[StringLength(255)]
[Sieve(CanSort = true)]
public string? Email { get; set; }
[Display(Name = "Phone")]
[StringLength(50)]
public string? ContactPhone { get; set; }
[Display(Name = "Birth date")]
[Required]
[Sieve(CanSort = true)]
public DateOnly? BirthDate { get; set; }
[Display(Name = "Document number")]
[Required]
[StringLength(50)]
public string DocumentNumber { get; set; } = string.Empty;
[Display(Name = "Country")]
[Required]
[StringLength(3)]
[Sieve(CanFilter = true)]
public string CountryCode { get; set; } = string.Empty;
[Display(Name = "Full name")]
public string FullName { get; set; } = string.Empty;
[Display(Name = "Full name (transcription)")]
[Sieve(CanFilter = true)]
public string FullNameTranscription { get; set; } = string.Empty;
[Display(Name = "Country")]
[Sieve(CanSort = true)]
public string CountryName { get; set; } = string.Empty;
[Display(Name = "Registrations")]
[Sieve(CanSort = true)]
public int RegistrationsCount { get; set; }
public List<SelectListItem> CountryOptions { get; set; } = [];
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Email) && string.IsNullOrWhiteSpace(ContactPhone))
{
yield return new ValidationResult(
Constants.Messages.EmailOrContactPhoneRequired,
new[] { nameof(Email), nameof(ContactPhone) });
}
}
}

View File

@@ -0,0 +1,52 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;
using Sieve.Attributes;
namespace Events.MVC.Models.Registrations;
public class RegistrationViewModel
{
[Sieve(CanSort = true)]
public int Id { get; set; }
[Required]
[Range(1, int.MaxValue)]
public int EventId { get; set; }
[Display(Name = "Person")]
[Required]
[Range(1, int.MaxValue)]
public int PersonId { get; set; }
[Display(Name = "Sport")]
[Required]
[Range(1, int.MaxValue)]
public int SportId { get; set; }
[Display(Name = "Person")]
public string PersonLookup { get; set; } = string.Empty;
[Display(Name = "Person")]
[Sieve(CanSort = true, CanFilter = true)]
public string PersonName { get; set; } = string.Empty;
[Display(Name = "Transcription")]
[Sieve(CanFilter = true)]
public string PersonTranscription { get; set; } = string.Empty;
[Display(Name = "Country")]
[Sieve(CanFilter = true)]
public string CountryCode { get; set; } = string.Empty;
public string CountryName { get; set; } = string.Empty;
[Display(Name = "Sport")]
[Sieve(CanSort = true)]
public string SportName { get; set; } = string.Empty;
[Display(Name = "Registered at")]
[Sieve(CanSort = true)]
public DateTime RegisteredAt { get; set; }
public List<SelectListItem> SportOptions { get; set; } = [];
}

View File

@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Events.MVC.Models.Registrations;
public class RegistrationsPageViewModel
{
public int SelectedEventId { get; set; }
public string SelectedEventName { get; set; } = string.Empty;
public List<SelectListItem> EventOptions { get; set; } = [];
public List<SelectListItem> CountryOptions { get; set; } = [];
public string CountryFilter { get; set; } = string.Empty;
public PagedList<RegistrationViewModel> Registrations { get; set; } = new([], new PagingInfo
{
ItemsPerPage = 10,
CurrentPage = 1
});
public RegistrationViewModel CreateModel { get; set; } = new();
public bool CanCreate { get; set; }
public string? CreateDisabledMessage { get; set; }
}

View File

@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
using Sieve.Attributes;
namespace Events.MVC.Models.Sports;
public class SportViewModel
{
[Sieve(CanSort = true)]
public int Id { get; set; }
[Display(Name = "Name")]
[Required]
[StringLength(100)]
[Sieve(CanSort = true, CanFilter = true)]
public string Name { get; set; } = string.Empty;
}