diff --git a/TheBank/BankContracts/AdapterContracts/IStorekeeperAdapter.cs b/TheBank/BankContracts/AdapterContracts/IStorekeeperAdapter.cs index e69e34c..faadfec 100644 --- a/TheBank/BankContracts/AdapterContracts/IStorekeeperAdapter.cs +++ b/TheBank/BankContracts/AdapterContracts/IStorekeeperAdapter.cs @@ -15,4 +15,6 @@ public interface IStorekeeperAdapter StorekeeperOperationResponse RegisterStorekeeper(StorekeeperBindingModel storekeeperModel); StorekeeperOperationResponse ChangeStorekeeperInfo(StorekeeperBindingModel storekeeperModel); + + StorekeeperOperationResponse Login(StorekeeperAuthBindingModel storekeeperModel, out string token); } diff --git a/TheBank/BankContracts/AdapterContracts/OperationResponses/StorekeeperOperationResponse.cs b/TheBank/BankContracts/AdapterContracts/OperationResponses/StorekeeperOperationResponse.cs index 85ccb7d..99a73df 100644 --- a/TheBank/BankContracts/AdapterContracts/OperationResponses/StorekeeperOperationResponse.cs +++ b/TheBank/BankContracts/AdapterContracts/OperationResponses/StorekeeperOperationResponse.cs @@ -8,6 +8,9 @@ public class StorekeeperOperationResponse : OperationResponse public static StorekeeperOperationResponse OK(List data) => OK>(data); + public static StorekeeperOperationResponse OK(string token) => + OK(token); + public static StorekeeperOperationResponse OK(StorekeeperViewModel data) => OK(data); @@ -21,4 +24,7 @@ public class StorekeeperOperationResponse : OperationResponse public static StorekeeperOperationResponse InternalServerError(string message) => InternalServerError(message); + + public static StorekeeperOperationResponse Unauthorized(string message) => + Unauthorized(message); } diff --git a/TheBank/BankContracts/BindingModels/StorekeeperAuthBindingModel.cs b/TheBank/BankContracts/BindingModels/StorekeeperAuthBindingModel.cs new file mode 100644 index 0000000..68bb5f2 --- /dev/null +++ b/TheBank/BankContracts/BindingModels/StorekeeperAuthBindingModel.cs @@ -0,0 +1,8 @@ +namespace BankContracts.BindingModels; + +public class StorekeeperAuthBindingModel +{ + public required string Login { get; set; } + + public required string Password { get; set; } +} diff --git a/TheBank/BankContracts/Infrastructure/OperationResponse.cs b/TheBank/BankContracts/Infrastructure/OperationResponse.cs index d3eafe6..3862295 100644 --- a/TheBank/BankContracts/Infrastructure/OperationResponse.cs +++ b/TheBank/BankContracts/Infrastructure/OperationResponse.cs @@ -46,4 +46,8 @@ public class OperationResponse protected static TResult InternalServerError(string? errorMessage = null) where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.InternalServerError, Result = errorMessage }; + + protected static TResult Unauthorized(string? errorMessage = null) + where TResult : OperationResponse, new() => + new() { StatusCode = HttpStatusCode.Unauthorized, Result = errorMessage }; } diff --git a/TheBank/BankDatabase/BankDatabase.csproj b/TheBank/BankDatabase/BankDatabase.csproj index 909458d..6565a76 100644 --- a/TheBank/BankDatabase/BankDatabase.csproj +++ b/TheBank/BankDatabase/BankDatabase.csproj @@ -9,6 +9,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/TheBank/BankDatabase/BankDbContext.cs b/TheBank/BankDatabase/BankDbContext.cs index ba34e52..4598c55 100644 --- a/TheBank/BankDatabase/BankDbContext.cs +++ b/TheBank/BankDatabase/BankDbContext.cs @@ -4,9 +4,14 @@ using Microsoft.EntityFrameworkCore; namespace BankDatabase; -internal class BankDbContext(IConfigurationDatabase configurationDatabase) : DbContext +public class BankDbContext : DbContext { - private readonly IConfigurationDatabase? _configurationDatabase = configurationDatabase; + private readonly IConfigurationDatabase? _configurationDatabase; + + public BankDbContext(IConfigurationDatabase configurationDatabase) + { + _configurationDatabase = configurationDatabase; + } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { @@ -33,7 +38,7 @@ internal class BankDbContext(IConfigurationDatabase configurationDatabase) : DbC modelBuilder.Entity() .HasIndex(x => x.Name) .IsUnique(); - + modelBuilder.Entity() .HasIndex(x => x.Abbreviation) .IsUnique(); @@ -80,17 +85,17 @@ internal class BankDbContext(IConfigurationDatabase configurationDatabase) : DbC public DbSet Clerks { get; set; } public DbSet Clients { get; set; } - + public DbSet CreditPrograms { get; set; } - + public DbSet Currencies { get; set; } - + public DbSet Deposits { get; set; } - + public DbSet Periods { get; set; } - + public DbSet Replenishments { get; set; } - + public DbSet Storekeepers { get; set; } public DbSet DepositCurrencies { get; set; } diff --git a/TheBank/BankDatabase/DesignTimeDbContextFactory.cs b/TheBank/BankDatabase/DesignTimeDbContextFactory.cs new file mode 100644 index 0000000..2395aab --- /dev/null +++ b/TheBank/BankDatabase/DesignTimeDbContextFactory.cs @@ -0,0 +1,17 @@ +using BankContracts.Infrastructure; +using Microsoft.EntityFrameworkCore.Design; + +namespace BankDatabase; + +public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory +{ + public BankDbContext CreateDbContext(string[] args) + { + return new BankDbContext(new ConfigurationDatabase()); + } +} + +internal class ConfigurationDatabase : IConfigurationDatabase +{ + public string ConnectionString => "Host=127.0.0.1;Port=5432;Database=BankTest;Username=postgres;Password=admin123;"; +} \ No newline at end of file diff --git a/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs b/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs new file mode 100644 index 0000000..8bed4ff --- /dev/null +++ b/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs @@ -0,0 +1,562 @@ +// +using System; +using BankDatabase; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BankDatabase.Migrations +{ + [DbContext(typeof(BankDbContext))] + [Migration("20250518195627_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BankDatabase.Models.Clerk", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.Property("MiddleName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Login") + .IsUnique(); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Clerks"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b => + { + b.Property("ClientId") + .HasColumnType("text"); + + b.Property("CreditProgramId") + .HasColumnType("text"); + + b.HasKey("ClientId", "CreditProgramId"); + + b.HasIndex("CreditProgramId"); + + b.ToTable("CreditProgramClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("MaxCost") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PeriodId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("PeriodId"); + + b.HasIndex("StorekeeperId"); + + b.ToTable("CreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b => + { + b.Property("CreditProgramId") + .HasColumnType("text"); + + b.Property("CurrencyId") + .HasColumnType("text"); + + b.HasKey("CreditProgramId", "CurrencyId"); + + b.HasIndex("CurrencyId"); + + b.ToTable("CurrencyCreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Abbreviation") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Abbreviation") + .IsUnique(); + + b.HasIndex("StorekeeperId"); + + b.ToTable("Currencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("InterestRate") + .HasColumnType("real"); + + b.Property("Period") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.ToTable("Deposits"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositClient", b => + { + b.Property("DepositId") + .HasColumnType("text"); + + b.Property("ClientId") + .HasColumnType("text"); + + b.HasKey("DepositId", "ClientId"); + + b.HasIndex("ClientId"); + + b.ToTable("DepositClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b => + { + b.Property("DepositId") + .HasColumnType("text"); + + b.Property("CurrencyId") + .HasColumnType("text"); + + b.HasKey("DepositId", "CurrencyId"); + + b.HasIndex("CurrencyId"); + + b.ToTable("DepositCurrencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("StorekeeperId"); + + b.ToTable("Periods"); + }); + + modelBuilder.Entity("BankDatabase.Models.Replenishment", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DepositId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.HasIndex("DepositId"); + + b.ToTable("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Storekeeper", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.Property("MiddleName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Login") + .IsUnique(); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Storekeepers"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Clients") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Clerk"); + }); + + modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b => + { + b.HasOne("BankDatabase.Models.Client", "Client") + .WithMany("CreditProgramClients") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram") + .WithMany("CreditProgramClients") + .HasForeignKey("CreditProgramId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + + b.Navigation("CreditProgram"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.HasOne("BankDatabase.Models.Period", "Period") + .WithMany("CreditPrograms") + .HasForeignKey("PeriodId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("CreditPrograms") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Period"); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b => + { + b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram") + .WithMany("CurrencyCreditPrograms") + .HasForeignKey("CreditProgramId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Currency", "Currency") + .WithMany("CurrencyCreditPrograms") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreditProgram"); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("Currencies") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Deposits") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Clerk"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositClient", b => + { + b.HasOne("BankDatabase.Models.Client", "Client") + .WithMany("DepositClients") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("DepositClients") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b => + { + b.HasOne("BankDatabase.Models.Currency", "Currency") + .WithMany("DepositCurrencies") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("DepositCurrencies") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("Periods") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.Replenishment", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Replenishments") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("Replenishments") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clerk"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.Clerk", b => + { + b.Navigation("Clients"); + + b.Navigation("Deposits"); + + b.Navigation("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.Navigation("CreditProgramClients"); + + b.Navigation("DepositClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.Navigation("CreditProgramClients"); + + b.Navigation("CurrencyCreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.Navigation("CurrencyCreditPrograms"); + + b.Navigation("DepositCurrencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.Navigation("DepositClients"); + + b.Navigation("DepositCurrencies"); + + b.Navigation("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.Navigation("CreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Storekeeper", b => + { + b.Navigation("CreditPrograms"); + + b.Navigation("Currencies"); + + b.Navigation("Periods"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs b/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs new file mode 100644 index 0000000..cd032d5 --- /dev/null +++ b/TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs @@ -0,0 +1,433 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BankDatabase.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Clerks", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Surname = table.Column(type: "text", nullable: false), + MiddleName = table.Column(type: "text", nullable: false), + Login = table.Column(type: "text", nullable: false), + Password = table.Column(type: "text", nullable: false), + Email = table.Column(type: "text", nullable: false), + PhoneNumber = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Clerks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Storekeepers", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Surname = table.Column(type: "text", nullable: false), + MiddleName = table.Column(type: "text", nullable: false), + Login = table.Column(type: "text", nullable: false), + Password = table.Column(type: "text", nullable: false), + Email = table.Column(type: "text", nullable: false), + PhoneNumber = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Storekeepers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Clients", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Surname = table.Column(type: "text", nullable: false), + Balance = table.Column(type: "numeric", nullable: false), + ClerkId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Clients", x => x.Id); + table.ForeignKey( + name: "FK_Clients_Clerks_ClerkId", + column: x => x.ClerkId, + principalTable: "Clerks", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Deposits", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + InterestRate = table.Column(type: "real", nullable: false), + Cost = table.Column(type: "numeric", nullable: false), + Period = table.Column(type: "integer", nullable: false), + ClerkId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Deposits", x => x.Id); + table.ForeignKey( + name: "FK_Deposits_Clerks_ClerkId", + column: x => x.ClerkId, + principalTable: "Clerks", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Currencies", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Abbreviation = table.Column(type: "text", nullable: false), + Cost = table.Column(type: "numeric", nullable: false), + StorekeeperId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Currencies", x => x.Id); + table.ForeignKey( + name: "FK_Currencies_Storekeepers_StorekeeperId", + column: x => x.StorekeeperId, + principalTable: "Storekeepers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Periods", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + StartTime = table.Column(type: "timestamp with time zone", nullable: false), + EndTime = table.Column(type: "timestamp with time zone", nullable: false), + StorekeeperId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Periods", x => x.Id); + table.ForeignKey( + name: "FK_Periods_Storekeepers_StorekeeperId", + column: x => x.StorekeeperId, + principalTable: "Storekeepers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "DepositClients", + columns: table => new + { + DepositId = table.Column(type: "text", nullable: false), + ClientId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DepositClients", x => new { x.DepositId, x.ClientId }); + table.ForeignKey( + name: "FK_DepositClients_Clients_ClientId", + column: x => x.ClientId, + principalTable: "Clients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_DepositClients_Deposits_DepositId", + column: x => x.DepositId, + principalTable: "Deposits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Replenishments", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Amount = table.Column(type: "numeric", nullable: false), + Date = table.Column(type: "timestamp with time zone", nullable: false), + DepositId = table.Column(type: "text", nullable: false), + ClerkId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Replenishments", x => x.Id); + table.ForeignKey( + name: "FK_Replenishments_Clerks_ClerkId", + column: x => x.ClerkId, + principalTable: "Clerks", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Replenishments_Deposits_DepositId", + column: x => x.DepositId, + principalTable: "Deposits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "DepositCurrencies", + columns: table => new + { + DepositId = table.Column(type: "text", nullable: false), + CurrencyId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DepositCurrencies", x => new { x.DepositId, x.CurrencyId }); + table.ForeignKey( + name: "FK_DepositCurrencies_Currencies_CurrencyId", + column: x => x.CurrencyId, + principalTable: "Currencies", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_DepositCurrencies_Deposits_DepositId", + column: x => x.DepositId, + principalTable: "Deposits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CreditPrograms", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Cost = table.Column(type: "numeric", nullable: false), + MaxCost = table.Column(type: "numeric", nullable: false), + StorekeeperId = table.Column(type: "text", nullable: false), + PeriodId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CreditPrograms", x => x.Id); + table.ForeignKey( + name: "FK_CreditPrograms_Periods_PeriodId", + column: x => x.PeriodId, + principalTable: "Periods", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CreditPrograms_Storekeepers_StorekeeperId", + column: x => x.StorekeeperId, + principalTable: "Storekeepers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CreditProgramClients", + columns: table => new + { + ClientId = table.Column(type: "text", nullable: false), + CreditProgramId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CreditProgramClients", x => new { x.ClientId, x.CreditProgramId }); + table.ForeignKey( + name: "FK_CreditProgramClients_Clients_ClientId", + column: x => x.ClientId, + principalTable: "Clients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CreditProgramClients_CreditPrograms_CreditProgramId", + column: x => x.CreditProgramId, + principalTable: "CreditPrograms", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CurrencyCreditPrograms", + columns: table => new + { + CreditProgramId = table.Column(type: "text", nullable: false), + CurrencyId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CurrencyCreditPrograms", x => new { x.CreditProgramId, x.CurrencyId }); + table.ForeignKey( + name: "FK_CurrencyCreditPrograms_CreditPrograms_CreditProgramId", + column: x => x.CreditProgramId, + principalTable: "CreditPrograms", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CurrencyCreditPrograms_Currencies_CurrencyId", + column: x => x.CurrencyId, + principalTable: "Currencies", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Clerks_Email", + table: "Clerks", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Clerks_Login", + table: "Clerks", + column: "Login", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Clerks_PhoneNumber", + table: "Clerks", + column: "PhoneNumber", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Clients_ClerkId", + table: "Clients", + column: "ClerkId"); + + migrationBuilder.CreateIndex( + name: "IX_CreditProgramClients_CreditProgramId", + table: "CreditProgramClients", + column: "CreditProgramId"); + + migrationBuilder.CreateIndex( + name: "IX_CreditPrograms_Name", + table: "CreditPrograms", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CreditPrograms_PeriodId", + table: "CreditPrograms", + column: "PeriodId"); + + migrationBuilder.CreateIndex( + name: "IX_CreditPrograms_StorekeeperId", + table: "CreditPrograms", + column: "StorekeeperId"); + + migrationBuilder.CreateIndex( + name: "IX_Currencies_Abbreviation", + table: "Currencies", + column: "Abbreviation", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Currencies_StorekeeperId", + table: "Currencies", + column: "StorekeeperId"); + + migrationBuilder.CreateIndex( + name: "IX_CurrencyCreditPrograms_CurrencyId", + table: "CurrencyCreditPrograms", + column: "CurrencyId"); + + migrationBuilder.CreateIndex( + name: "IX_DepositClients_ClientId", + table: "DepositClients", + column: "ClientId"); + + migrationBuilder.CreateIndex( + name: "IX_DepositCurrencies_CurrencyId", + table: "DepositCurrencies", + column: "CurrencyId"); + + migrationBuilder.CreateIndex( + name: "IX_Deposits_ClerkId", + table: "Deposits", + column: "ClerkId"); + + migrationBuilder.CreateIndex( + name: "IX_Periods_StorekeeperId", + table: "Periods", + column: "StorekeeperId"); + + migrationBuilder.CreateIndex( + name: "IX_Replenishments_ClerkId", + table: "Replenishments", + column: "ClerkId"); + + migrationBuilder.CreateIndex( + name: "IX_Replenishments_DepositId", + table: "Replenishments", + column: "DepositId"); + + migrationBuilder.CreateIndex( + name: "IX_Storekeepers_Email", + table: "Storekeepers", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Storekeepers_Login", + table: "Storekeepers", + column: "Login", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Storekeepers_PhoneNumber", + table: "Storekeepers", + column: "PhoneNumber", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CreditProgramClients"); + + migrationBuilder.DropTable( + name: "CurrencyCreditPrograms"); + + migrationBuilder.DropTable( + name: "DepositClients"); + + migrationBuilder.DropTable( + name: "DepositCurrencies"); + + migrationBuilder.DropTable( + name: "Replenishments"); + + migrationBuilder.DropTable( + name: "CreditPrograms"); + + migrationBuilder.DropTable( + name: "Clients"); + + migrationBuilder.DropTable( + name: "Currencies"); + + migrationBuilder.DropTable( + name: "Deposits"); + + migrationBuilder.DropTable( + name: "Periods"); + + migrationBuilder.DropTable( + name: "Clerks"); + + migrationBuilder.DropTable( + name: "Storekeepers"); + } + } +} diff --git a/TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs b/TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs new file mode 100644 index 0000000..f52a695 --- /dev/null +++ b/TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs @@ -0,0 +1,559 @@ +// +using System; +using BankDatabase; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BankDatabase.Migrations +{ + [DbContext(typeof(BankDbContext))] + partial class BankDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BankDatabase.Models.Clerk", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.Property("MiddleName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Login") + .IsUnique(); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Clerks"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b => + { + b.Property("ClientId") + .HasColumnType("text"); + + b.Property("CreditProgramId") + .HasColumnType("text"); + + b.HasKey("ClientId", "CreditProgramId"); + + b.HasIndex("CreditProgramId"); + + b.ToTable("CreditProgramClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("MaxCost") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PeriodId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("PeriodId"); + + b.HasIndex("StorekeeperId"); + + b.ToTable("CreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b => + { + b.Property("CreditProgramId") + .HasColumnType("text"); + + b.Property("CurrencyId") + .HasColumnType("text"); + + b.HasKey("CreditProgramId", "CurrencyId"); + + b.HasIndex("CurrencyId"); + + b.ToTable("CurrencyCreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Abbreviation") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Abbreviation") + .IsUnique(); + + b.HasIndex("StorekeeperId"); + + b.ToTable("Currencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cost") + .HasColumnType("numeric"); + + b.Property("InterestRate") + .HasColumnType("real"); + + b.Property("Period") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.ToTable("Deposits"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositClient", b => + { + b.Property("DepositId") + .HasColumnType("text"); + + b.Property("ClientId") + .HasColumnType("text"); + + b.HasKey("DepositId", "ClientId"); + + b.HasIndex("ClientId"); + + b.ToTable("DepositClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b => + { + b.Property("DepositId") + .HasColumnType("text"); + + b.Property("CurrencyId") + .HasColumnType("text"); + + b.HasKey("DepositId", "CurrencyId"); + + b.HasIndex("CurrencyId"); + + b.ToTable("DepositCurrencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("StorekeeperId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("StorekeeperId"); + + b.ToTable("Periods"); + }); + + modelBuilder.Entity("BankDatabase.Models.Replenishment", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("ClerkId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DepositId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClerkId"); + + b.HasIndex("DepositId"); + + b.ToTable("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Storekeeper", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.Property("MiddleName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Surname") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Login") + .IsUnique(); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Storekeepers"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Clients") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Clerk"); + }); + + modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b => + { + b.HasOne("BankDatabase.Models.Client", "Client") + .WithMany("CreditProgramClients") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram") + .WithMany("CreditProgramClients") + .HasForeignKey("CreditProgramId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + + b.Navigation("CreditProgram"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.HasOne("BankDatabase.Models.Period", "Period") + .WithMany("CreditPrograms") + .HasForeignKey("PeriodId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("CreditPrograms") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Period"); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b => + { + b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram") + .WithMany("CurrencyCreditPrograms") + .HasForeignKey("CreditProgramId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Currency", "Currency") + .WithMany("CurrencyCreditPrograms") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreditProgram"); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("Currencies") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Deposits") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Clerk"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositClient", b => + { + b.HasOne("BankDatabase.Models.Client", "Client") + .WithMany("DepositClients") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("DepositClients") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b => + { + b.HasOne("BankDatabase.Models.Currency", "Currency") + .WithMany("DepositCurrencies") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("DepositCurrencies") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper") + .WithMany("Periods") + .HasForeignKey("StorekeeperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Storekeeper"); + }); + + modelBuilder.Entity("BankDatabase.Models.Replenishment", b => + { + b.HasOne("BankDatabase.Models.Clerk", "Clerk") + .WithMany("Replenishments") + .HasForeignKey("ClerkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("BankDatabase.Models.Deposit", "Deposit") + .WithMany("Replenishments") + .HasForeignKey("DepositId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clerk"); + + b.Navigation("Deposit"); + }); + + modelBuilder.Entity("BankDatabase.Models.Clerk", b => + { + b.Navigation("Clients"); + + b.Navigation("Deposits"); + + b.Navigation("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Client", b => + { + b.Navigation("CreditProgramClients"); + + b.Navigation("DepositClients"); + }); + + modelBuilder.Entity("BankDatabase.Models.CreditProgram", b => + { + b.Navigation("CreditProgramClients"); + + b.Navigation("CurrencyCreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Currency", b => + { + b.Navigation("CurrencyCreditPrograms"); + + b.Navigation("DepositCurrencies"); + }); + + modelBuilder.Entity("BankDatabase.Models.Deposit", b => + { + b.Navigation("DepositClients"); + + b.Navigation("DepositCurrencies"); + + b.Navigation("Replenishments"); + }); + + modelBuilder.Entity("BankDatabase.Models.Period", b => + { + b.Navigation("CreditPrograms"); + }); + + modelBuilder.Entity("BankDatabase.Models.Storekeeper", b => + { + b.Navigation("CreditPrograms"); + + b.Navigation("Currencies"); + + b.Navigation("Periods"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TheBank/BankDatabase/Models/Clerk.cs b/TheBank/BankDatabase/Models/Clerk.cs index eb95fb6..87689f6 100644 --- a/TheBank/BankDatabase/Models/Clerk.cs +++ b/TheBank/BankDatabase/Models/Clerk.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Clerk +public class Clerk { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/Client.cs b/TheBank/BankDatabase/Models/Client.cs index 8fe53fd..3765367 100644 --- a/TheBank/BankDatabase/Models/Client.cs +++ b/TheBank/BankDatabase/Models/Client.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Client +public class Client { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/ClientCreditProgram.cs b/TheBank/BankDatabase/Models/ClientCreditProgram.cs index 04bd615..244fedc 100644 --- a/TheBank/BankDatabase/Models/ClientCreditProgram.cs +++ b/TheBank/BankDatabase/Models/ClientCreditProgram.cs @@ -1,6 +1,8 @@ -namespace BankDatabase.Models; +using System.ComponentModel.DataAnnotations.Schema; -class ClientCreditProgram +namespace BankDatabase.Models; + +public class ClientCreditProgram { public required string ClientId { get; set; } diff --git a/TheBank/BankDatabase/Models/CreditProgram.cs b/TheBank/BankDatabase/Models/CreditProgram.cs index 1069b36..8d78d5a 100644 --- a/TheBank/BankDatabase/Models/CreditProgram.cs +++ b/TheBank/BankDatabase/Models/CreditProgram.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class CreditProgram +public class CreditProgram { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/CreditProgramCurrency.cs b/TheBank/BankDatabase/Models/CreditProgramCurrency.cs index 186f6bd..c0f8a0f 100644 --- a/TheBank/BankDatabase/Models/CreditProgramCurrency.cs +++ b/TheBank/BankDatabase/Models/CreditProgramCurrency.cs @@ -1,6 +1,8 @@ -namespace BankDatabase.Models; +using System.ComponentModel.DataAnnotations.Schema; -class CreditProgramCurrency +namespace BankDatabase.Models; + +public class CreditProgramCurrency { public required string CreditProgramId { get; set; } diff --git a/TheBank/BankDatabase/Models/Currency.cs b/TheBank/BankDatabase/Models/Currency.cs index 989ebf5..03fd5f7 100644 --- a/TheBank/BankDatabase/Models/Currency.cs +++ b/TheBank/BankDatabase/Models/Currency.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Currency +public class Currency { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/Deposit.cs b/TheBank/BankDatabase/Models/Deposit.cs index 47851a2..ea0c546 100644 --- a/TheBank/BankDatabase/Models/Deposit.cs +++ b/TheBank/BankDatabase/Models/Deposit.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Deposit +public class Deposit { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/DepositClient.cs b/TheBank/BankDatabase/Models/DepositClient.cs index ba4940b..5e83700 100644 --- a/TheBank/BankDatabase/Models/DepositClient.cs +++ b/TheBank/BankDatabase/Models/DepositClient.cs @@ -1,6 +1,8 @@ -namespace BankDatabase.Models; +using System.ComponentModel.DataAnnotations.Schema; -class DepositClient +namespace BankDatabase.Models; + +public class DepositClient { public required string DepositId { get; set; } diff --git a/TheBank/BankDatabase/Models/DepositCurrency.cs b/TheBank/BankDatabase/Models/DepositCurrency.cs index c6dae95..b439165 100644 --- a/TheBank/BankDatabase/Models/DepositCurrency.cs +++ b/TheBank/BankDatabase/Models/DepositCurrency.cs @@ -1,6 +1,8 @@ -namespace BankDatabase.Models; +using System.ComponentModel.DataAnnotations.Schema; -class DepositCurrency +namespace BankDatabase.Models; + +public class DepositCurrency { public required string DepositId { get; set; } diff --git a/TheBank/BankDatabase/Models/Period.cs b/TheBank/BankDatabase/Models/Period.cs index b60dd1a..4a6849c 100644 --- a/TheBank/BankDatabase/Models/Period.cs +++ b/TheBank/BankDatabase/Models/Period.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Period +public class Period { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/Replenishment.cs b/TheBank/BankDatabase/Models/Replenishment.cs index 19ac963..2492744 100644 --- a/TheBank/BankDatabase/Models/Replenishment.cs +++ b/TheBank/BankDatabase/Models/Replenishment.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Replenishment +public class Replenishment { public required string Id { get; set; } diff --git a/TheBank/BankDatabase/Models/Storekeeper.cs b/TheBank/BankDatabase/Models/Storekeeper.cs index 0ff6863..c697101 100644 --- a/TheBank/BankDatabase/Models/Storekeeper.cs +++ b/TheBank/BankDatabase/Models/Storekeeper.cs @@ -2,7 +2,7 @@ namespace BankDatabase.Models; -class Storekeeper +public class Storekeeper { public required string Id { get; set; } diff --git a/TheBank/BankTests/Infrastructure/ConfigurationDatabase.cs b/TheBank/BankTests/Infrastructure/ConfigurationDatabase.cs index f319e22..665c4a0 100644 --- a/TheBank/BankTests/Infrastructure/ConfigurationDatabase.cs +++ b/TheBank/BankTests/Infrastructure/ConfigurationDatabase.cs @@ -5,5 +5,5 @@ namespace BankTests.Infrastructure; internal class ConfigurationDatabase : IConfigurationDatabase { public string ConnectionString => - "Host=127.0.0.1;Port=5432;Database=TitanicTest;Username=postgres;Password=postgres;Include Error Detail=true"; + "Host=127.0.0.1;Port=5432;Database=TitanicTest;Username=postgres;Password=admin123;Include Error Detail=true"; } diff --git a/TheBank/BankWebApi/Adapters/StorekeeperAdapter.cs b/TheBank/BankWebApi/Adapters/StorekeeperAdapter.cs index d287373..28f168d 100644 --- a/TheBank/BankWebApi/Adapters/StorekeeperAdapter.cs +++ b/TheBank/BankWebApi/Adapters/StorekeeperAdapter.cs @@ -7,6 +7,8 @@ using BankContracts.BusinessLogicContracts; using BankContracts.DataModels; using BankContracts.Exceptions; using BankContracts.ViewModels; +using BankWebApi.Infrastructure; +using System.Buffers; namespace BankWebApi.Adapters; @@ -14,11 +16,13 @@ public class StorekeeperAdapter : IStorekeeperAdapter { private readonly IStorekeeperBusinessLogicContract _storekeeperBusinessLogicContract; + private readonly IJwtProvider _jwtProvider; + private readonly ILogger _logger; private readonly Mapper _mapper; - public StorekeeperAdapter(IStorekeeperBusinessLogicContract storekeeperBusinessLogicContract, ILogger logger) + public StorekeeperAdapter(IStorekeeperBusinessLogicContract storekeeperBusinessLogicContract, IJwtProvider jwtProvider, ILogger logger) { _storekeeperBusinessLogicContract = storekeeperBusinessLogicContract; _logger = logger; @@ -28,6 +32,7 @@ public class StorekeeperAdapter : IStorekeeperAdapter cfg.CreateMap(); }); _mapper = new Mapper(config); + _jwtProvider = jwtProvider; } public StorekeeperOperationResponse GetList() @@ -119,7 +124,7 @@ public class StorekeeperAdapter : IStorekeeperAdapter { _logger.LogError(ex, "StorageException"); return StorekeeperOperationResponse.BadRequest( - $"Error while working with data storage: {ex.InnerException!.Message}" + $"Error while working with data storage: {ex.InnerException?.Message}" ); } catch (Exception ex) @@ -170,5 +175,31 @@ public class StorekeeperAdapter : IStorekeeperAdapter _logger.LogError(ex, "Exception"); return StorekeeperOperationResponse.InternalServerError(ex.Message); } - } + } + + public StorekeeperOperationResponse Login(StorekeeperAuthBindingModel storekeeperAuth, out string token) + { + token = string.Empty; + try + { + var storekeeper = _storekeeperBusinessLogicContract.GetStorekeeperByData(storekeeperAuth.Login); + + + var result = storekeeperAuth.Password == storekeeper.Password; + + if (!result) + { + return StorekeeperOperationResponse.Unauthorized("Password are incorrect"); + } + + token = _jwtProvider.GenerateToken(storekeeper); + + return StorekeeperOperationResponse.OK(token); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception in Login"); + return StorekeeperOperationResponse.InternalServerError($"Exception in Login {ex.Message}"); + } + } } diff --git a/TheBank/BankWebApi/AuthOptions.cs b/TheBank/BankWebApi/AuthOptions.cs index f9e7702..ea5af13 100644 --- a/TheBank/BankWebApi/AuthOptions.cs +++ b/TheBank/BankWebApi/AuthOptions.cs @@ -9,6 +9,7 @@ namespace BankWebApi; /// public class AuthOptions { + public const string CookieName = "bank"; public const string ISSUER = "Bank_AuthServer"; // издатель токена public const string AUDIENCE = "Bank_AuthClient"; // потребитель токена const string KEY = "banksuperpupersecret_secretsecretsecretkey!"; // ключ для шифрации diff --git a/TheBank/BankWebApi/BankWebApi.csproj b/TheBank/BankWebApi/BankWebApi.csproj index dbae776..d9974b1 100644 --- a/TheBank/BankWebApi/BankWebApi.csproj +++ b/TheBank/BankWebApi/BankWebApi.csproj @@ -7,6 +7,7 @@ + diff --git a/TheBank/BankWebApi/Controllers/StorekeepersController.cs b/TheBank/BankWebApi/Controllers/StorekeepersController.cs index 97726ea..74683d2 100644 --- a/TheBank/BankWebApi/Controllers/StorekeepersController.cs +++ b/TheBank/BankWebApi/Controllers/StorekeepersController.cs @@ -39,7 +39,8 @@ public class StorekeepersController(IStorekeeperAdapter adapter) : ControllerBas /// /// модель от пользователя /// - [HttpPost] + [HttpPost("register")] + [AllowAnonymous] public IActionResult Register([FromBody] StorekeeperBindingModel model) { return _adapter.RegisterStorekeeper(model).GetResponse(Request, Response); @@ -55,4 +56,20 @@ public class StorekeepersController(IStorekeeperAdapter adapter) : ControllerBas { return _adapter.ChangeStorekeeperInfo(model).GetResponse(Request, Response); } + + /// + /// вход для кладовщика + /// + /// модель с логином и паролем + /// + [HttpPost("login")] + [AllowAnonymous] + public IActionResult Login([FromBody] StorekeeperAuthBindingModel model) + { + var res = _adapter.Login(model, out string token); + + Response.Cookies.Append(AuthOptions.CookieName, token); + + return res.GetResponse(Request, Response); + } } diff --git a/TheBank/BankWebApi/Infrastructure/IJwtProvider.cs b/TheBank/BankWebApi/Infrastructure/IJwtProvider.cs new file mode 100644 index 0000000..8ff9981 --- /dev/null +++ b/TheBank/BankWebApi/Infrastructure/IJwtProvider.cs @@ -0,0 +1,8 @@ +using BankContracts.DataModels; + +namespace BankWebApi.Infrastructure; + +public interface IJwtProvider +{ + string GenerateToken(StorekeeperDataModel dataModel); +} diff --git a/TheBank/BankWebApi/Infrastructure/JwtProvider.cs b/TheBank/BankWebApi/Infrastructure/JwtProvider.cs new file mode 100644 index 0000000..a95c1f2 --- /dev/null +++ b/TheBank/BankWebApi/Infrastructure/JwtProvider.cs @@ -0,0 +1,21 @@ +using BankContracts.DataModels; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; + +namespace BankWebApi.Infrastructure; + +public class JwtProvider : IJwtProvider +{ + public string GenerateToken(StorekeeperDataModel dataModel) + { + var token = new JwtSecurityToken( + issuer: AuthOptions.ISSUER, + audience: AuthOptions.AUDIENCE, + claims: [new("id", dataModel.Id)], + expires: DateTime.UtcNow.Add(TimeSpan.FromDays(2)), + signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256)); + + return new JwtSecurityTokenHandler().WriteToken(token); + } +} diff --git a/TheBank/BankWebApi/Infrastructure/PasswordHelper.cs b/TheBank/BankWebApi/Infrastructure/PasswordHelper.cs new file mode 100644 index 0000000..4a00cb0 --- /dev/null +++ b/TheBank/BankWebApi/Infrastructure/PasswordHelper.cs @@ -0,0 +1,7 @@ +namespace BankWebApi.Infrastructure; + +public class PasswordHelper +{ + public static string HashPassword(string password) => BCrypt.Net.BCrypt.HashPassword(password); + public static bool VerifyPassword(string password, string hash) => BCrypt.Net.BCrypt.Verify(password, hash); +} diff --git a/TheBank/BankWebApi/Program.cs b/TheBank/BankWebApi/Program.cs index ef05435..27d6334 100644 --- a/TheBank/BankWebApi/Program.cs +++ b/TheBank/BankWebApi/Program.cs @@ -28,12 +28,11 @@ builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Bank API", Version = "v1" }); - // XML- ( ) + // Включение XML-комментариев (если они есть) var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath, includeControllerXmlComments: true); - // JWT- Swagger UI c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: 'Bearer {token}'", @@ -78,6 +77,16 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(), ValidateIssuerSigningKey = true, + + }; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + context.Token = context.Request.Cookies[AuthOptions.CookieName]; + + return Task.CompletedTask; + } }; }); @@ -87,13 +96,14 @@ builder.Services.AddCors(options => { policy.WithOrigins("http://localhost:26312") .AllowAnyMethod() - .AllowAnyHeader(); + .AllowAnyHeader() + .AllowCredentials(); }); }); // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); -builder.Services.AddSingleton(); -// +builder.Services.AddSingleton(); +// ������ ������ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); @@ -102,7 +112,7 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); -// +// �� builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); @@ -112,7 +122,7 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); -// +// �������� builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); @@ -121,6 +131,8 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +// shit +builder.Services.AddTransient(); var app = builder.Build(); @@ -132,7 +144,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Bank API V1"); - c.RoutePrefix = "swagger"; // Swagger UI /swagger + c.RoutePrefix = "swagger"; // Swagger UI ����� �������� �� /swagger }); } if (app.Environment.IsProduction()) @@ -146,9 +158,17 @@ if (app.Environment.IsProduction()) } app.UseCors("AllowFrontend"); app.UseHttpsRedirection(); + +app.UseCookiePolicy(new CookiePolicyOptions +{ + HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always, + Secure = CookieSecurePolicy.Always +}); + app.UseAuthentication(); app.UseAuthorization(); +// это для тестов app.Map("/login/{username}", (string username) => { return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken( diff --git a/TheBank/bankui/bun.lockb b/TheBank/bankui/bun.lockb index 8581920..4884d45 100644 Binary files a/TheBank/bankui/bun.lockb and b/TheBank/bankui/bun.lockb differ diff --git a/TheBank/bankui/package-lock.json b/TheBank/bankui/package-lock.json new file mode 100644 index 0000000..179a33b --- /dev/null +++ b/TheBank/bankui/package-lock.json @@ -0,0 +1,3602 @@ +{ + "name": "bankui", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bankui", + "version": "0.0.0", + "dependencies": { + "@hookform/resolvers": "^5.0.1", + "@radix-ui/react-avatar": "^1.1.9", + "@radix-ui/react-checkbox": "^1.3.1", + "@radix-ui/react-dialog": "^1.1.13", + "@radix-ui/react-dropdown-menu": "^2.1.14", + "@radix-ui/react-label": "^2.1.6", + "@radix-ui/react-menubar": "^1.1.14", + "@radix-ui/react-select": "^2.2.4", + "@radix-ui/react-separator": "^1.1.6", + "@radix-ui/react-slot": "^1.2.2", + "@radix-ui/react-tabs": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.6", + "@tailwindcss/vite": "^4.1.7", + "@tanstack/react-query": "^5.76.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.511.0", + "next-themes": "^0.4.6", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-hook-form": "^7.56.4", + "react-router-dom": "^7.6.0", + "sonner": "^2.0.3", + "tailwind-merge": "^3.3.0", + "tailwindcss": "^4.1.7", + "tw-animate-css": "^1.3.0", + "zod": "^3.24.4" + }, + "devDependencies": { + "@eslint/js": "^9.25.0", + "@types/node": "^22.15.18", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@vitejs/plugin-react": "^4.4.1", + "eslint": "^9.25.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.30.1", + "vite": "^6.3.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.27.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.0", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.0", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "license": "MIT" + }, + "node_modules/@hookform/resolvers": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.14", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.6", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-roving-focus": "1.1.9", + "@radix-ui/react-slot": "1.2.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.14", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-roving-focus": "1.1.9", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.4", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.11.tgz", + "integrity": "sha512-4FiKSVoXqPP/KfzlB7lwwqoFV6EPwkrrqGp9cUYXjwDYHhvpnqq79P+EPHKcdoTE7Rl8w/+6s9rTlsfXHES9GA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-roving-focus": "1.1.9", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.9", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.2", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.7", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.7" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.7", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-x64": "4.1.7", + "@tailwindcss/oxide-freebsd-x64": "4.1.7", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.7", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.7", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-x64-musl": "4.1.7", + "@tailwindcss/oxide-wasm32-wasi": "4.1.7", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.7", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.7" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.7", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.7", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.7", + "@tailwindcss/oxide": "4.1.7", + "tailwindcss": "4.1.7" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.76.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.76.1", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.76.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.18", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.4", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.5", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/type-utils": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.5", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001718", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "devOptional": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.155", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.4", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.4.4", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.4.2", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/lucide-react": { + "version": "0.511.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.56.4", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.6.0", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.6.0", + "license": "MIT", + "dependencies": { + "react-router": "7.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.40.2", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.2", + "@rollup/rollup-android-arm64": "4.40.2", + "@rollup/rollup-darwin-arm64": "4.40.2", + "@rollup/rollup-darwin-x64": "4.40.2", + "@rollup/rollup-freebsd-arm64": "4.40.2", + "@rollup/rollup-freebsd-x64": "4.40.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", + "@rollup/rollup-linux-arm-musleabihf": "4.40.2", + "@rollup/rollup-linux-arm64-gnu": "4.40.2", + "@rollup/rollup-linux-arm64-musl": "4.40.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-musl": "4.40.2", + "@rollup/rollup-linux-s390x-gnu": "4.40.2", + "@rollup/rollup-linux-x64-gnu": "4.40.2", + "@rollup/rollup-linux-x64-musl": "4.40.2", + "@rollup/rollup-win32-arm64-msvc": "4.40.2", + "@rollup/rollup-win32-ia32-msvc": "4.40.2", + "@rollup/rollup-win32-x64-msvc": "4.40.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sonner": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.3.tgz", + "integrity": "sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tailwind-merge": { + "version": "3.3.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.7", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/tw-animate-css": { + "version": "1.3.0", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.32.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.32.1", + "@typescript-eslint/parser": "8.32.1", + "@typescript-eslint/utils": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.24.4", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/TheBank/bankui/package.json b/TheBank/bankui/package.json index aa9c0a4..ede19ab 100644 --- a/TheBank/bankui/package.json +++ b/TheBank/bankui/package.json @@ -20,16 +20,19 @@ "@radix-ui/react-select": "^2.2.4", "@radix-ui/react-separator": "^1.1.6", "@radix-ui/react-slot": "^1.2.2", + "@radix-ui/react-tabs": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.6", "@tailwindcss/vite": "^4.1.7", "@tanstack/react-query": "^5.76.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.511.0", + "next-themes": "^0.4.6", "react": "^19.1.0", "react-dom": "^19.1.0", "react-hook-form": "^7.56.4", "react-router-dom": "^7.6.0", + "sonner": "^2.0.3", "tailwind-merge": "^3.3.0", "tailwindcss": "^4.1.7", "tw-animate-css": "^1.3.0", diff --git a/TheBank/bankui/src/api/api.ts b/TheBank/bankui/src/api/api.ts index 646fcf6..467a59e 100644 --- a/TheBank/bankui/src/api/api.ts +++ b/TheBank/bankui/src/api/api.ts @@ -8,6 +8,7 @@ import type { PeriodBindingModel, ReplenishmentBindingModel, StorekeeperBindingModel, + LoginBindingModel, } from '../types/types'; // Clients API @@ -117,4 +118,5 @@ export const storekeepersApi = { postData('api/Storekeepers/Register', data), update: (data: StorekeeperBindingModel) => putData('api/Storekeepers/ChangeInfo', data), + login: (data: LoginBindingModel) => postData('api/Storekeepers/login', data), }; diff --git a/TheBank/bankui/src/api/client.ts b/TheBank/bankui/src/api/client.ts index 155525c..5ae7153 100644 --- a/TheBank/bankui/src/api/client.ts +++ b/TheBank/bankui/src/api/client.ts @@ -7,6 +7,7 @@ export async function getData(path: string): Promise { headers: { mode: 'no-cors', }, + credentials: 'include', }); if (!res.ok) { throw new Error(`Не получается загрузить ${path}: ${res.statusText}`); @@ -22,6 +23,7 @@ export async function postData(path: string, data: T) { 'Content-Type': 'application/json', mode: 'no-cors', }, + credentials: 'include', body: JSON.stringify(data), }); if (!res.ok) { @@ -36,6 +38,7 @@ export async function putData(path: string, data: T) { 'Content-Type': 'application/json', mode: 'no-cors', }, + credentials: 'include', body: JSON.stringify(data), }); if (!res.ok) { diff --git a/TheBank/bankui/src/components/features/LoginForm.tsx b/TheBank/bankui/src/components/features/LoginForm.tsx new file mode 100644 index 0000000..d5dd132 --- /dev/null +++ b/TheBank/bankui/src/components/features/LoginForm.tsx @@ -0,0 +1,82 @@ +import type { LoginBindingModel } from '@/types/types'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '../ui/form'; +import { Input } from '../ui/input'; +import { Button } from '../ui/button'; + +interface LoginFormProps { + onSubmit: (data: LoginBindingModel) => void; + defaultValues?: Partial; +} +const loginFormSchema = z.object({ + login: z.string().min(3, 'Логин должен быть не короче 3 символов'), + password: z.string().min(6, 'Пароль должен быть не короче 6 символов'), +}); + +type FormValues = z.infer; + +export const LoginForm = ({ + onSubmit, + defaultValues, +}: LoginFormProps): React.JSX.Element => { + const form = useForm({ + resolver: zodResolver(loginFormSchema), + defaultValues: { + login: defaultValues?.login || '', + password: defaultValues?.password || '', + }, + }); + + const handleSubmit = (data: FormValues) => { + const payload: LoginBindingModel = { + ...data, + }; + onSubmit(payload); + }; + + return ( +
+ + ( + + Логин + + + + + + )} + /> + ( + + Пароль + + + + + + )} + /> + + + + ); +}; diff --git a/TheBank/bankui/src/components/features/RegisterForm.tsx b/TheBank/bankui/src/components/features/RegisterForm.tsx new file mode 100644 index 0000000..050f4f5 --- /dev/null +++ b/TheBank/bankui/src/components/features/RegisterForm.tsx @@ -0,0 +1,166 @@ +import React from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import type { StorekeeperBindingModel } from '@/types/types'; + +interface RegisterFormProps { + onSubmit: (data: StorekeeperBindingModel) => void; + defaultValues?: Partial; +} + +const registerFormSchema = z.object({ + id: z.string().optional(), + name: z.string().min(1, 'Имя обязательно'), + surname: z.string().min(1, 'Фамилия обязательна'), + middleName: z.string().min(1, 'Отчество обязательно'), + login: z.string().min(3, 'Логин должен быть не короче 3 символов'), + password: z.string().min(6, 'Пароль должен быть не короче 6 символов'), + email: z.string().email('Введите корректный email'), + phoneNumber: z.string().min(10, 'Введите корректный номер телефона'), +}); + +type FormValues = z.infer; + +export const RegisterForm = ({ + onSubmit, + defaultValues, +}: RegisterFormProps): React.JSX.Element => { + const form = useForm({ + resolver: zodResolver(registerFormSchema), + defaultValues: { + id: defaultValues?.id || crypto.randomUUID(), + name: defaultValues?.name || '', + surname: defaultValues?.surname || '', + middleName: defaultValues?.middleName || '', + login: defaultValues?.login || '', + password: defaultValues?.password || '', + email: defaultValues?.email || '', + phoneNumber: defaultValues?.phoneNumber || '', + }, + }); + + const handleSubmit = (data: FormValues) => { + const payload: StorekeeperBindingModel = { + ...data, + id: data.id || crypto.randomUUID(), + }; + onSubmit(payload); + }; + + return ( +
+ + } + /> + ( + + Имя + + + + + + )} + /> + ( + + Фамилия + + + + + + )} + /> + ( + + Отчество + + + + + + )} + /> + ( + + Логин + + + + + + )} + /> + ( + + Пароль + + + + + + )} + /> + ( + + Email + + + + + + )} + /> + ( + + Номер телефона + + + + + + )} + /> + + + + ); +}; diff --git a/TheBank/bankui/src/components/layout/Header.tsx b/TheBank/bankui/src/components/layout/Header.tsx index bf0cb26..23bd142 100644 --- a/TheBank/bankui/src/components/layout/Header.tsx +++ b/TheBank/bankui/src/components/layout/Header.tsx @@ -15,7 +15,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '../ui/dropdown-menu'; -import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'; +import { Avatar, AvatarFallback } from '../ui/avatar'; import { Button } from '../ui/button'; type NavOptionValue = { diff --git a/TheBank/bankui/src/components/pages/AuthStorekeeper.tsx b/TheBank/bankui/src/components/pages/AuthStorekeeper.tsx new file mode 100644 index 0000000..ebfdd27 --- /dev/null +++ b/TheBank/bankui/src/components/pages/AuthStorekeeper.tsx @@ -0,0 +1,50 @@ +import { useStorekeepers } from '@/hooks/useStorekeepers'; +import React from 'react'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs'; +import { RegisterForm } from '../features/RegisterForm'; +import type { LoginBindingModel, StorekeeperBindingModel } from '@/types/types'; +import { LoginForm } from '../features/LoginForm'; +import { Toaster } from '../ui/sonner'; +import { toast } from 'sonner'; + +export const AuthStorekeeper = (): React.JSX.Element => { + const { createStorekeeper, loginStorekeeper, isLoginError, loginError } = + useStorekeepers(); + + const handleRegister = (data: StorekeeperBindingModel) => { + console.log(data); + createStorekeeper(data); + }; + const handleLogin = (data: LoginBindingModel) => { + console.log(data); + loginStorekeeper(data); + }; + + React.useEffect(() => { + if (isLoginError) { + toast(`Ошибка ${loginError?.message}`); + } + }, [isLoginError, loginError]); + + return ( + <> +
+
+ + + Вход + Регистрация + + + + + + + + +
+
+ + + ); +}; diff --git a/TheBank/bankui/src/components/pages/CreditPrograms.tsx b/TheBank/bankui/src/components/pages/CreditPrograms.tsx index 8f515dd..54453ed 100644 --- a/TheBank/bankui/src/components/pages/CreditPrograms.tsx +++ b/TheBank/bankui/src/components/pages/CreditPrograms.tsx @@ -43,9 +43,8 @@ export const CreditPrograms = (): React.JSX.Element => { isOpen={isDialogOpen} onClose={() => setIsDialogOpen(false)} onSubmit={handleAdd} - > - - + children={} + />
diff --git a/TheBank/bankui/src/components/ui/sonner.tsx b/TheBank/bankui/src/components/ui/sonner.tsx new file mode 100644 index 0000000..225d010 --- /dev/null +++ b/TheBank/bankui/src/components/ui/sonner.tsx @@ -0,0 +1,23 @@ +import { useTheme } from 'next-themes'; +import { Toaster as Sonner, type ToasterProps } from 'sonner'; + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = 'system' } = useTheme(); + + return ( + + ); +}; + +export { Toaster }; diff --git a/TheBank/bankui/src/components/ui/tabs.tsx b/TheBank/bankui/src/components/ui/tabs.tsx new file mode 100644 index 0000000..3d6f3ac --- /dev/null +++ b/TheBank/bankui/src/components/ui/tabs.tsx @@ -0,0 +1,64 @@ +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +function Tabs({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/TheBank/bankui/src/hooks/useStorekeepers.ts b/TheBank/bankui/src/hooks/useStorekeepers.ts index 41405c3..3a6c52d 100644 --- a/TheBank/bankui/src/hooks/useStorekeepers.ts +++ b/TheBank/bankui/src/hooks/useStorekeepers.ts @@ -7,33 +7,48 @@ export const useStorekeepers = () => { const { data: storekeepers, isLoading, - isError, + isError: isGetAllError, error, } = useQuery({ queryKey: ['storekeepers'], queryFn: storekeepersApi.getAll, }); - const { mutate: createStorekeeper } = useMutation({ + const { mutate: createStorekeeper, isError: isCreateError } = useMutation({ mutationFn: storekeepersApi.create, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['storekeepers'] }); }, }); - const { mutate: updateStorekeeper } = useMutation({ + const { mutate: updateStorekeeper, isError: isUpdateError } = useMutation({ mutationFn: storekeepersApi.update, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['storekeepers'] }); }, }); + const { + mutate: loginStorekeeper, + isError: isLoginError, + error: loginError, + } = useMutation({ + mutationFn: storekeepersApi.login, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['storekeepers'] }); + }, + }); + return { storekeepers, isLoading, - isError, + isGetAllError, + isCreateError, + isLoginError, + loginError, error, createStorekeeper, + loginStorekeeper, updateStorekeeper, }; }; diff --git a/TheBank/bankui/src/main.tsx b/TheBank/bankui/src/main.tsx index 158ba16..068fcd2 100644 --- a/TheBank/bankui/src/main.tsx +++ b/TheBank/bankui/src/main.tsx @@ -6,6 +6,7 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { Currencies } from './components/pages/Currencies.tsx'; import { CreditPrograms } from './components/pages/CreditPrograms.tsx'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { AuthStorekeeper } from './components/pages/AuthStorekeeper.tsx'; const routes = createBrowserRouter([ { @@ -23,6 +24,10 @@ const routes = createBrowserRouter([ ], errorElement:

бля пизда рулям

, }, + { + path: '/auth', + element: , + }, ]); const queryClient = new QueryClient(); diff --git a/TheBank/bankui/src/types/types.ts b/TheBank/bankui/src/types/types.ts index 8689ee7..26139f5 100644 --- a/TheBank/bankui/src/types/types.ts +++ b/TheBank/bankui/src/types/types.ts @@ -89,3 +89,8 @@ export interface StorekeeperBindingModel { email?: string; phoneNumber?: string; } + +export interface LoginBindingModel { + login: string; + password: string; +}