diff --git a/TicketOffice/Data/TicketOfficeContext.cs b/TicketOffice/Data/TicketOfficeContext.cs index 670b41e..f4554dc 100644 --- a/TicketOffice/Data/TicketOfficeContext.cs +++ b/TicketOffice/Data/TicketOfficeContext.cs @@ -18,8 +18,9 @@ namespace TicketOffice.Data public DbSet User { get; set; } public DbSet Route { get; set; } - - public DbSet City { get; set; } + + public DbSet RouteCity { get; set; } + public DbSet TicketCity { get; set; } public DbSet Ticket { get; set; } } diff --git a/TicketOffice/Migrations/20220404151700_InitialCreate.Designer.cs b/TicketOffice/Migrations/20220526065734_Initial_Create.Designer.cs similarity index 76% rename from TicketOffice/Migrations/20220404151700_InitialCreate.Designer.cs rename to TicketOffice/Migrations/20220526065734_Initial_Create.Designer.cs index 3e8a357..8983d3b 100644 --- a/TicketOffice/Migrations/20220404151700_InitialCreate.Designer.cs +++ b/TicketOffice/Migrations/20220526065734_Initial_Create.Designer.cs @@ -11,15 +11,32 @@ using TicketOffice.Data; namespace TicketOffice.Migrations { [DbContext(typeof(TicketOfficeContext))] - [Migration("20220404151700_InitialCreate")] - partial class InitialCreate + [Migration("20220526065734_Initial_Create")] + partial class Initial_Create { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "6.0.3"); - modelBuilder.Entity("TicketOffice.Models.City", b => + modelBuilder.Entity("TicketOffice.Models.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Capacity") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Route"); + }); + + modelBuilder.Entity("TicketOffice.Models.RouteCity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -43,24 +60,7 @@ namespace TicketOffice.Migrations b.HasIndex("RouteId"); - b.ToTable("City"); - }); - - modelBuilder.Entity("TicketOffice.Models.Route", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Capacity") - .HasColumnType("INTEGER"); - - b.Property("Number") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("Route"); + b.ToTable("RouteCity"); }); modelBuilder.Entity("TicketOffice.Models.Ticket", b => @@ -95,6 +95,33 @@ namespace TicketOffice.Migrations b.ToTable("Ticket"); }); + modelBuilder.Entity("TicketOffice.Models.TicketCity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArrivalTime") + .HasColumnType("TEXT"); + + b.Property("DepartureTime") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(24) + .HasColumnType("TEXT"); + + b.Property("TicketId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketCity"); + }); + modelBuilder.Entity("TicketOffice.Models.User", b => { b.Property("Id") @@ -131,7 +158,7 @@ namespace TicketOffice.Migrations b.ToTable("User"); }); - modelBuilder.Entity("TicketOffice.Models.City", b => + modelBuilder.Entity("TicketOffice.Models.RouteCity", b => { b.HasOne("TicketOffice.Models.Route", "Route") .WithMany("Cities") @@ -161,6 +188,17 @@ namespace TicketOffice.Migrations b.Navigation("User"); }); + modelBuilder.Entity("TicketOffice.Models.TicketCity", b => + { + b.HasOne("TicketOffice.Models.Ticket", "Ticket") + .WithMany("Cities") + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + }); + modelBuilder.Entity("TicketOffice.Models.Route", b => { b.Navigation("Cities"); @@ -168,6 +206,11 @@ namespace TicketOffice.Migrations b.Navigation("Tickets"); }); + modelBuilder.Entity("TicketOffice.Models.Ticket", b => + { + b.Navigation("Cities"); + }); + modelBuilder.Entity("TicketOffice.Models.User", b => { b.Navigation("Tickets"); diff --git a/TicketOffice/Migrations/20220404151700_InitialCreate.cs b/TicketOffice/Migrations/20220526065734_Initial_Create.cs similarity index 74% rename from TicketOffice/Migrations/20220404151700_InitialCreate.cs rename to TicketOffice/Migrations/20220526065734_Initial_Create.cs index a1ece00..5ed937a 100644 --- a/TicketOffice/Migrations/20220404151700_InitialCreate.cs +++ b/TicketOffice/Migrations/20220526065734_Initial_Create.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace TicketOffice.Migrations { - public partial class InitialCreate : Migration + public partial class Initial_Create : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -42,7 +42,7 @@ namespace TicketOffice.Migrations }); migrationBuilder.CreateTable( - name: "City", + name: "RouteCity", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) @@ -54,9 +54,9 @@ namespace TicketOffice.Migrations }, constraints: table => { - table.PrimaryKey("PK_City", x => x.Id); + table.PrimaryKey("PK_RouteCity", x => x.Id); table.ForeignKey( - name: "FK_City_Route_RouteId", + name: "FK_RouteCity_Route_RouteId", column: x => x.RouteId, principalTable: "Route", principalColumn: "Id", @@ -92,9 +92,31 @@ namespace TicketOffice.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "TicketCity", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", maxLength: 24, nullable: false), + ArrivalTime = table.Column(type: "TEXT", nullable: true), + DepartureTime = table.Column(type: "TEXT", nullable: true), + TicketId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TicketCity", x => x.Id); + table.ForeignKey( + name: "FK_TicketCity_Ticket_TicketId", + column: x => x.TicketId, + principalTable: "Ticket", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateIndex( - name: "IX_City_RouteId", - table: "City", + name: "IX_RouteCity_RouteId", + table: "RouteCity", column: "RouteId"); migrationBuilder.CreateIndex( @@ -106,12 +128,20 @@ namespace TicketOffice.Migrations name: "IX_Ticket_UserId", table: "Ticket", column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_TicketCity_TicketId", + table: "TicketCity", + column: "TicketId"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "City"); + name: "RouteCity"); + + migrationBuilder.DropTable( + name: "TicketCity"); migrationBuilder.DropTable( name: "Ticket"); diff --git a/TicketOffice/Migrations/TicketOfficeContextModelSnapshot.cs b/TicketOffice/Migrations/TicketOfficeContextModelSnapshot.cs index 6125266..ac4e9a7 100644 --- a/TicketOffice/Migrations/TicketOfficeContextModelSnapshot.cs +++ b/TicketOffice/Migrations/TicketOfficeContextModelSnapshot.cs @@ -17,7 +17,24 @@ namespace TicketOffice.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "6.0.3"); - modelBuilder.Entity("TicketOffice.Models.City", b => + modelBuilder.Entity("TicketOffice.Models.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Capacity") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Route"); + }); + + modelBuilder.Entity("TicketOffice.Models.RouteCity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -41,24 +58,7 @@ namespace TicketOffice.Migrations b.HasIndex("RouteId"); - b.ToTable("City"); - }); - - modelBuilder.Entity("TicketOffice.Models.Route", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Capacity") - .HasColumnType("INTEGER"); - - b.Property("Number") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("Route"); + b.ToTable("RouteCity"); }); modelBuilder.Entity("TicketOffice.Models.Ticket", b => @@ -93,6 +93,33 @@ namespace TicketOffice.Migrations b.ToTable("Ticket"); }); + modelBuilder.Entity("TicketOffice.Models.TicketCity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArrivalTime") + .HasColumnType("TEXT"); + + b.Property("DepartureTime") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(24) + .HasColumnType("TEXT"); + + b.Property("TicketId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketCity"); + }); + modelBuilder.Entity("TicketOffice.Models.User", b => { b.Property("Id") @@ -129,7 +156,7 @@ namespace TicketOffice.Migrations b.ToTable("User"); }); - modelBuilder.Entity("TicketOffice.Models.City", b => + modelBuilder.Entity("TicketOffice.Models.RouteCity", b => { b.HasOne("TicketOffice.Models.Route", "Route") .WithMany("Cities") @@ -159,6 +186,17 @@ namespace TicketOffice.Migrations b.Navigation("User"); }); + modelBuilder.Entity("TicketOffice.Models.TicketCity", b => + { + b.HasOne("TicketOffice.Models.Ticket", "Ticket") + .WithMany("Cities") + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + }); + modelBuilder.Entity("TicketOffice.Models.Route", b => { b.Navigation("Cities"); @@ -166,6 +204,11 @@ namespace TicketOffice.Migrations b.Navigation("Tickets"); }); + modelBuilder.Entity("TicketOffice.Models.Ticket", b => + { + b.Navigation("Cities"); + }); + modelBuilder.Entity("TicketOffice.Models.User", b => { b.Navigation("Tickets"); diff --git a/TicketOffice/Models/Route.cs b/TicketOffice/Models/Route.cs index 4a11840..a017041 100644 --- a/TicketOffice/Models/Route.cs +++ b/TicketOffice/Models/Route.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.AspNetCore.Components; using Microsoft.EntityFrameworkCore; namespace TicketOffice.Models; @@ -8,8 +9,7 @@ public class Route { [Key] public int Id { get; set; } - - + [Required(ErrorMessage = "Поле має бути заповненим")] [Display(Name = "Номер")] [Range(1, 256)] @@ -19,9 +19,9 @@ public class Route [Display(Name = "Ємність")] [Range(5, 40)] public int Capacity { get; set; } - [Required] - public ICollection Cities { get; set; } + public ICollection Cities { get; set; } + public ICollection? Tickets { get; set; } } \ No newline at end of file diff --git a/TicketOffice/Models/City.cs b/TicketOffice/Models/RouteCity.cs similarity index 97% rename from TicketOffice/Models/City.cs rename to TicketOffice/Models/RouteCity.cs index f6eaea7..5152f2b 100644 --- a/TicketOffice/Models/City.cs +++ b/TicketOffice/Models/RouteCity.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace TicketOffice.Models; -public class City +public class RouteCity { [Key] public int Id { get; set; } @@ -21,7 +21,6 @@ public class City [Display(Name = "Дата прибуття")] [DataType(DataType.Date)] public DateTime? DepartureTime { get; set; } - [ForeignKey("Route")] public int RouteId { get; set; } diff --git a/TicketOffice/Models/SeedData.cs b/TicketOffice/Models/SeedData.cs index 042d502..6d35456 100644 --- a/TicketOffice/Models/SeedData.cs +++ b/TicketOffice/Models/SeedData.cs @@ -16,7 +16,7 @@ public class SeedData throw new ArgumentNullException("Null TicketOfficeContext"); } - if (context.User.Any() | context.Route.Any() | context.City.Any() | context.Ticket.Any()) + if (context.User.Any() | context.Route.Any() | context.RouteCity.Any() | context.Ticket.Any()) { return; // Data has been seeded } @@ -44,21 +44,21 @@ public class SeedData new Route { Number = 2, Capacity = 30, - Cities = new City[] + Cities = new RouteCity[] { - new City + new RouteCity { Name = "Кремінна", ArrivalTime = new DateTime(2022, 03, 28, 8, 15, 0), DepartureTime = new DateTime(2022, 03, 28, 8, 35, 0), }, - new City + new RouteCity { Name = "Рубіжне", ArrivalTime = new DateTime(2022, 03, 28, 9, 5, 0), DepartureTime = new DateTime(2022, 03, 28, 9, 25, 0), }, - new City + new RouteCity { Name = "Сєвєродонецьк", ArrivalTime = new DateTime(2022, 03, 28, 9, 55, 0) @@ -69,21 +69,21 @@ public class SeedData { Number = 1, Capacity = 25, - Cities = new City[] + Cities = new RouteCity[] { - new City + new RouteCity { Name = "Сєвєродонецьк", ArrivalTime = new DateTime(2022, 03, 28, 15, 55, 0), DepartureTime = new DateTime(2022, 03, 28, 16, 15, 0), }, - new City + new RouteCity { Name = "Рубіжне", ArrivalTime = new DateTime(2022, 03, 28, 16, 45, 0), DepartureTime = new DateTime(2022, 03, 28, 17, 5, 0), }, - new City + new RouteCity { Name = "Кремінна", ArrivalTime = new DateTime(2022, 03, 28, 17, 40, 0) @@ -94,27 +94,27 @@ public class SeedData { Number = 3, Capacity = 30, - Cities = new City[] + Cities = new RouteCity[] { - new City + new RouteCity { Name = "Кремінна", ArrivalTime = new DateTime(2022, 03, 28, 9, 20, 0), DepartureTime = new DateTime(2022, 03, 28, 8, 40, 0), }, - new City + new RouteCity { Name = "Житлівка", ArrivalTime = new DateTime(2022, 03, 28, 10, 0, 0), DepartureTime = new DateTime(2022, 03, 28, 10, 15, 0), }, - new City + new RouteCity { Name = "Рубіжне", ArrivalTime = new DateTime(2022, 03, 28, 11, 5, 0), DepartureTime = new DateTime(2022, 03, 28, 11, 20, 0), }, - new City + new RouteCity { Name = "Сєвєродонецьк", ArrivalTime = new DateTime(2022, 03, 28, 11, 55, 0) diff --git a/TicketOffice/Models/Ticket.cs b/TicketOffice/Models/Ticket.cs index db6bbbc..419ad26 100644 --- a/TicketOffice/Models/Ticket.cs +++ b/TicketOffice/Models/Ticket.cs @@ -19,8 +19,10 @@ public class Ticket [Required(ErrorMessage = "Поле має бути заповненим")] [Display(Name = "Номер місця пасажира")] public int PassengerPlace { get; set; } - - + + [Required] + public ICollection Cities { get; set; } + [ForeignKey("User")] public int UserId { get; set; } public User User { get; set; } diff --git a/TicketOffice/Models/TicketCity.cs b/TicketOffice/Models/TicketCity.cs new file mode 100644 index 0000000..548b280 --- /dev/null +++ b/TicketOffice/Models/TicketCity.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TicketOffice.Models; + +public class TicketCity +{ + [Key] + public int Id { get; set; } + + [MaxLength(24, ErrorMessage = "Назва міста не може бути більше 24 символів"), + MinLength(2, ErrorMessage = "Назва міста не може бути менше 2 символів")] + [Display(Name = "Назва міста")] + [Required(ErrorMessage = "Поле має бути заповненим")] + public string Name { get; set; } + + [Display(Name = "Дата відправлення")] + [DataType(DataType.Date)] + public DateTime? ArrivalTime { get; set; } + + [Display(Name = "Дата прибуття")] + [DataType(DataType.Date)] + public DateTime? DepartureTime { get; set; } + + [ForeignKey("Ticket")] + public int TicketId { get; set; } + public Ticket Ticket { get; set; } +} \ No newline at end of file diff --git a/TicketOffice/Pages/Auth/Account.cshtml b/TicketOffice/Pages/Auth/Account.cshtml index 90b89ce..cec9bae 100644 --- a/TicketOffice/Pages/Auth/Account.cshtml +++ b/TicketOffice/Pages/Auth/Account.cshtml @@ -37,17 +37,17 @@
Дата відправлення: - @ticket.Route.Cities.First().DepartureTime?.ToString("f").Split(",")[0].ToLower(), - @ticket.Route.Cities.First().DepartureTime?.ToString("dd.MM.yyyy"), - @ticket.Route.Cities.First().DepartureTime?.ToString("HH:mm") + @ticket.Cities.First().DepartureTime?.ToString("f").Split(",")[0].ToLower(), + @ticket.Cities.First().DepartureTime?.ToString("dd.MM.yyyy"), + @ticket.Cities.First().DepartureTime?.ToString("HH:mm")
Дата прибуття: - @ticket.Route.Cities.Last().ArrivalTime?.ToString("f").Split(",")[0].ToLower(), - @ticket.Route.Cities.Last().ArrivalTime?.ToString("dd.MM.yyyy"), - @ticket.Route.Cities.Last().ArrivalTime?.ToString("HH:mm") + @ticket.Cities.Last().ArrivalTime?.ToString("f").Split(",")[0].ToLower(), + @ticket.Cities.Last().ArrivalTime?.ToString("dd.MM.yyyy"), + @ticket.Cities.Last().ArrivalTime?.ToString("HH:mm")
@@ -62,11 +62,11 @@ } -
- -
-
Керування аккаунтом
-
+@*
*@ +@* *@ +@*
*@ +@*
Керування аккаунтом
*@ +@*
*@ @* Popup windows *@ @@ -103,30 +103,30 @@ Відправлення - @ticket.Route.Cities.First().Name + @ticket.Cities.First().Name - - @ticket.Route.Cities.First().DepartureTime?.ToString("HH:mm") + @ticket.Cities.First().DepartureTime?.ToString("HH:mm") - @for (int i = 1; i < ticket.Route.Cities.Count - 1; i++) + @for (int i = 1; i < ticket.Cities.Count - 1; i++) { Проміжна станція - @ticket.Route.Cities.ToList()[i].Name + @ticket.Cities.ToList()[i].Name - @ticket.Route.Cities.ToList()[i].ArrivalTime?.ToString("HH:mm") + @ticket.Cities.ToList()[i].ArrivalTime?.ToString("HH:mm") - @ticket.Route.Cities.ToList()[i].DepartureTime?.ToString("HH:mm") + @ticket.Cities.ToList()[i].DepartureTime?.ToString("HH:mm") } @@ -136,10 +136,10 @@ Прибуття - @ticket.Route.Cities.Last().Name + @ticket.Cities.Last().Name - @ticket.Route.Cities.Last().ArrivalTime?.ToString("HH:mm") + @ticket.Cities.Last().ArrivalTime?.ToString("HH:mm") - diff --git a/TicketOffice/Pages/Auth/Account.cshtml.cs b/TicketOffice/Pages/Auth/Account.cshtml.cs index ec52b18..863d430 100644 --- a/TicketOffice/Pages/Auth/Account.cshtml.cs +++ b/TicketOffice/Pages/Auth/Account.cshtml.cs @@ -12,15 +12,13 @@ public class IndexModel : PageModel [BindProperty(SupportsGet = true)] public int ReturnTicketId { get; set; } private readonly TicketOfficeContext _context; - private readonly ILogger _logger; - + public IndexModel(TicketOfficeContext context, ILogger logger) { _context = context; - _logger = logger; } - public IActionResult OnGet() + public ActionResult OnGet() { if (!ValidateSession()) return RedirectToPage("/Auth/Login"); @@ -28,18 +26,16 @@ public class IndexModel : PageModel Tickets = _context.Ticket .Where(t => t.UserId == HttpContext.Session.GetInt32("UserId")) .Include(t => t.Route) - .Include(t => t.Route.Cities) + .Include(t => t.Cities) .ToList(); return Page(); } - public IActionResult OnGetReturnTicket() + public ActionResult OnGetReturnTicket() { OnGet(); - - _logger.Log(LogLevel.Information, $"\n\n\n\n {ReturnTicketId} \n\n\n\n"); - + Ticket returnTicket = _context.Ticket.Find(ReturnTicketId); if (returnTicket is not null) diff --git a/TicketOffice/Pages/Routes/Index.cshtml b/TicketOffice/Pages/Routes/Index.cshtml index c326855..439d8f6 100644 --- a/TicketOffice/Pages/Routes/Index.cshtml +++ b/TicketOffice/Pages/Routes/Index.cshtml @@ -164,7 +164,7 @@ @($"{duration?.TotalHours.ToString().Split(",")[0]}:{duration?.Minutes}") - @(route.Capacity - route.Tickets.Count) + @Model.GetRemainingCapacity(route) Обрати @@ -311,7 +311,7 @@ @for (int i = 1; i <= route.Capacity; i++) { - if (route.Tickets.Any(t => t.PassengerPlace == i)) + if (route.Tickets.Any(t => @Model.GetCitiesNames(t.Cities.ToList()).Intersect(@Model.GetCitiesNames(route.Cities.ToList())).ToList().Any() && t.PassengerPlace == i)) { } diff --git a/TicketOffice/Pages/Routes/Index.cshtml.cs b/TicketOffice/Pages/Routes/Index.cshtml.cs index ca3263b..f146e8b 100644 --- a/TicketOffice/Pages/Routes/Index.cshtml.cs +++ b/TicketOffice/Pages/Routes/Index.cshtml.cs @@ -15,10 +15,12 @@ public class IndexModel : PageModel public string PassengerLastNameValidationError; public string PassengerFirstNameValidationError; public string PassengerPlaceValidationError; - + [BindProperty(SupportsGet = true)] public string From { get; set; } [BindProperty(SupportsGet = true)] public string To { get; set; } + [BindProperty(SupportsGet = true)] public DateTime Date { get; set; } = new DateTime(2022, 03, 28, 0, 0, 0).Date; + [BindProperty(SupportsGet = true)] public string SortString { get; set; } private readonly TicketOfficeContext _context; @@ -30,40 +32,29 @@ public class IndexModel : PageModel public ActionResult OnGet() { - if (!string.IsNullOrWhiteSpace(From) || !string.IsNullOrWhiteSpace(To)) - { - RetrieveAllRoutes(); - } - - if (!string.IsNullOrWhiteSpace(From)) - { - FilterRoutesByFrom(); - } - - if (!string.IsNullOrWhiteSpace(To)) - { - FilterRoutesByTo(); - } - - if (!string.IsNullOrWhiteSpace(From) || !string.IsNullOrWhiteSpace(To)) - { - FilterRoutesByDate(); - } - + GetRoutes(); return Page(); } public ActionResult OnPost() { - if (!PassengerNameValidation(Ticket.PassengerLastName, out PassengerLastNameValidationError) | !PassengerNameValidation(Ticket.PassengerFirstName, out PassengerFirstNameValidationError) | !PassengerPlaceValidation(Ticket.PassengerPlace, out PassengerPlaceValidationError)) + if (!PassengerNameValidation(Ticket.PassengerLastName, + out PassengerLastNameValidationError) | + !PassengerNameValidation(Ticket.PassengerFirstName, + out PassengerFirstNameValidationError) | + !PassengerPlaceValidation(Ticket.PassengerPlace, + out PassengerPlaceValidationError)) return OnGet(); - + + GetRoutes(); + CopyCitiesToTicket(); _context.Ticket.Add(Ticket); + RevertChangesToRouteCities(); _context.SaveChanges(); - + return RedirectToPage("/Auth/Account"); } - + public void OnGetSortByNumber() { OnGet(); @@ -85,17 +76,20 @@ public class IndexModel : PageModel Routes.Sort((x, y) => { TimeSpan? totalDuration; - + if (SortString == "increasingDeparture") { - totalDuration = x.Cities.First().DepartureTime - y.Cities.First().DepartureTime; + totalDuration = x.Cities.First().DepartureTime - + y.Cities.First().DepartureTime; } else { - totalDuration = y.Cities.First().DepartureTime - x.Cities.First().DepartureTime; + totalDuration = y.Cities.First().DepartureTime - + x.Cities.First().DepartureTime; } - return Math.Clamp((int)totalDuration.Value.TotalMilliseconds, -1, 1); + return Math.Clamp((int) totalDuration.Value.TotalMilliseconds, -1, + 1); }); } @@ -109,14 +103,17 @@ public class IndexModel : PageModel if (SortString == "increasingArrival") { - totalDuration = x.Cities.Last().ArrivalTime - y.Cities.Last().ArrivalTime; + totalDuration = x.Cities.Last().ArrivalTime - + y.Cities.Last().ArrivalTime; } else { - totalDuration = y.Cities.Last().ArrivalTime - x.Cities.Last().ArrivalTime; + totalDuration = y.Cities.Last().ArrivalTime - + x.Cities.Last().ArrivalTime; } - - return Math.Clamp((int)totalDuration.Value.TotalMilliseconds, -1, 1); + + return Math.Clamp((int) totalDuration.Value.TotalMilliseconds, -1, + 1); }); } @@ -126,8 +123,10 @@ public class IndexModel : PageModel Routes.Sort((x, y) => { - TimeSpan? xDuration = x.Cities.Last().ArrivalTime - x.Cities.First().DepartureTime; - TimeSpan? yDuration = y.Cities.Last().ArrivalTime - y.Cities.First().DepartureTime; + TimeSpan? xDuration = x.Cities.Last().ArrivalTime - + x.Cities.First().DepartureTime; + TimeSpan? yDuration = y.Cities.Last().ArrivalTime - + y.Cities.First().DepartureTime; TimeSpan? totalDuration; if (SortString == "increasingDuration") @@ -139,31 +138,76 @@ public class IndexModel : PageModel totalDuration = yDuration - xDuration; } - return Math.Clamp((int)totalDuration.Value.TotalMilliseconds, -1, 1); + return Math.Clamp((int) totalDuration.Value.TotalMilliseconds, -1, + 1); }); } + public List GetCitiesNames(List Cities) + { + List citiesNames = new List(); + + foreach (var city in Cities) + { + citiesNames.Add(city.Name); + } + + return citiesNames; + } + + public List GetCitiesNames(List Cities) + { + List citiesNames = new List(); + + foreach (var city in Cities) + { + citiesNames.Add(city.Name); + } + + return citiesNames; + } + + public int GetRemainingCapacity(Route route) + { + return route.Capacity - route.Tickets.Count(t => + GetCitiesNames(t.Cities.ToList()) + .Intersect(GetCitiesNames(route.Cities.ToList())) + .ToList().Any()); + } + + private void RetrieveAllRoutes() { Routes = _context.Route .Include(r => r.Cities) .Include(r => r.Tickets) .ToList(); + + // Add cities to tickets + for (int i = 0; i < Routes.Count; i++) + { + for (int j = 0; j < Routes[i].Tickets.Count; j++) + { + Routes[i].Tickets.ToList()[j].Cities = _context.TicketCity + .Where(tc => tc.Ticket == Routes[i].Tickets.ToList()[j]) + .ToList(); + } + } } private void FilterRoutesByFrom() { - + Routes.ForEach(r => r.Cities = r.Cities .SkipWhile(c => c.Name.ToLower() != From.Trim().ToLower()) .ToList()); Routes.RemoveAll(r => r.Cities.Count < 2); } - + private void FilterRoutesByTo() { - + Routes.ForEach(r => r.Cities = r.Cities .Reverse().SkipWhile(c => c.Name.ToLower() != To.Trim().ToLower()) .Reverse().ToList()); @@ -173,10 +217,35 @@ public class IndexModel : PageModel private void FilterRoutesByDate() { - Routes.RemoveAll(r => r.Cities.First().DepartureTime.Value.DayOfYear != Date.DayOfYear); + Routes.RemoveAll(r => + r.Cities.First().DepartureTime.Value.DayOfYear != Date.DayOfYear); } - private bool PassengerNameValidation(string? name, out string validationError) + private void GetRoutes() + { + if (!string.IsNullOrWhiteSpace(From) || !string.IsNullOrWhiteSpace(To)) + { + RetrieveAllRoutes(); + } + + if (!string.IsNullOrWhiteSpace(From)) + { + FilterRoutesByFrom(); + } + + if (!string.IsNullOrWhiteSpace(To)) + { + FilterRoutesByTo(); + } + + if (!string.IsNullOrWhiteSpace(From) || !string.IsNullOrWhiteSpace(To)) + { + FilterRoutesByDate(); + } + } + + private bool PassengerNameValidation(string? name, + out string validationError) { if (String.IsNullOrEmpty(name)) { @@ -196,15 +265,39 @@ public class IndexModel : PageModel return false; } - Ticket? ticket = _context.Ticket.FirstOrDefault(t => t.RouteId == Ticket.RouteId && t.PassengerPlace == Ticket.PassengerPlace); + Ticket? ticket = _context.Ticket.FirstOrDefault(t => + t.RouteId == Ticket.RouteId && + t.PassengerPlace == Ticket.PassengerPlace); if (ticket is not null) { validationError = "Місце вже зайняте"; return false; } - + validationError = String.Empty; return true; } + + private void CopyCitiesToTicket() + { + List RouteCities = Routes.Find(r => r.Id == Ticket.RouteId).Cities.ToList(); + Ticket.Cities = new List(); + foreach (var city in RouteCities) + { + Ticket.Cities.Add(new TicketCity + { + Name = city.Name, + DepartureTime = city.DepartureTime, + ArrivalTime = city.ArrivalTime + }); + } + } + + private void RevertChangesToRouteCities() + { + _context.ChangeTracker.Entries() + .Where(e => e.Metadata.Name == "TicketOffice.Models.RouteCity") + .ToList().ForEach(e => e.State = EntityState.Unchanged); + } } \ No newline at end of file diff --git a/TicketOffice/Pages/Shared/_Layout.cshtml b/TicketOffice/Pages/Shared/_Layout.cshtml index 257325a..37ded2c 100644 --- a/TicketOffice/Pages/Shared/_Layout.cshtml +++ b/TicketOffice/Pages/Shared/_Layout.cshtml @@ -24,7 +24,7 @@
@if (Context.Session.GetString("UserId") != null) { - Аккаунт + Мої квитки } else { diff --git a/TicketOffice/wwwroot/css/CityListPopup.css b/TicketOffice/wwwroot/css/CityListPopup.css index 21e6fad..ff4f564 100644 --- a/TicketOffice/wwwroot/css/CityListPopup.css +++ b/TicketOffice/wwwroot/css/CityListPopup.css @@ -11,7 +11,8 @@ .popup-city-list { width: 40rem; - height: 30rem; + height: fit-content; + max-height: 30rem; background: #eaeef1; position: fixed; top: calc(50% - 15rem); diff --git a/TicketOffice/wwwroot/css/Index.css b/TicketOffice/wwwroot/css/Index.css index 1231f84..f763f0a 100644 --- a/TicketOffice/wwwroot/css/Index.css +++ b/TicketOffice/wwwroot/css/Index.css @@ -11,7 +11,7 @@ body { } div.background { - background-image: url("https://tinyurl.com/24kx479s"); + background-image: url("../img/yutong-u12-electric-bus.jpg"); height: calc(100vh - 3.15rem); background-position: center; background-repeat: no-repeat; diff --git a/TicketOffice/wwwroot/css/InfoPopup.css b/TicketOffice/wwwroot/css/InfoPopup.css index 032663d..0e3af92 100644 --- a/TicketOffice/wwwroot/css/InfoPopup.css +++ b/TicketOffice/wwwroot/css/InfoPopup.css @@ -11,7 +11,7 @@ .popup-info { width: 30rem; - height: 13rem; + height: fit-content; background: #eaeef1; position: fixed; top: calc(50% - 6.5rem); @@ -33,8 +33,8 @@ .popup-info-body { width: calc(100% - 2rem); - height: calc(100% - 8rem); - padding: 0.5rem 1rem; + height: fit-content; + padding: 1rem 1rem; display: flex; justify-content: center; align-items: center; diff --git a/TicketOffice/wwwroot/img/yutong-u12-electric-bus.jpg b/TicketOffice/wwwroot/img/yutong-u12-electric-bus.jpg new file mode 100644 index 0000000..e853be0 Binary files /dev/null and b/TicketOffice/wwwroot/img/yutong-u12-electric-bus.jpg differ