From e8f493691f25e6da0625ba50f037d1c855cc0308 Mon Sep 17 00:00:00 2001 From: DjonniStorm Date: Mon, 19 May 2025 00:13:37 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D0=B4=D0=BE=D0=B2=D1=89=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdapterContracts/IStorekeeperAdapter.cs | 2 + .../StorekeeperOperationResponse.cs | 6 + .../StorekeeperAuthBindingModel.cs | 8 + .../Infrastructure/OperationResponse.cs | 4 + TheBank/BankDatabase/BankDatabase.csproj | 4 + TheBank/BankDatabase/BankDbContext.cs | 23 +- .../DesignTimeDbContextFactory.cs | 17 + .../20250518195627_InitialCreate.Designer.cs | 562 +++ .../20250518195627_InitialCreate.cs | 433 ++ .../Migrations/BankDbContextModelSnapshot.cs | 559 +++ TheBank/BankDatabase/Models/Clerk.cs | 2 +- TheBank/BankDatabase/Models/Client.cs | 2 +- .../Models/ClientCreditProgram.cs | 6 +- TheBank/BankDatabase/Models/CreditProgram.cs | 2 +- .../Models/CreditProgramCurrency.cs | 6 +- TheBank/BankDatabase/Models/Currency.cs | 2 +- TheBank/BankDatabase/Models/Deposit.cs | 2 +- TheBank/BankDatabase/Models/DepositClient.cs | 6 +- .../BankDatabase/Models/DepositCurrency.cs | 6 +- TheBank/BankDatabase/Models/Period.cs | 2 +- TheBank/BankDatabase/Models/Replenishment.cs | 2 +- TheBank/BankDatabase/Models/Storekeeper.cs | 2 +- .../Infrastructure/ConfigurationDatabase.cs | 2 +- .../BankWebApi/Adapters/StorekeeperAdapter.cs | 37 +- TheBank/BankWebApi/AuthOptions.cs | 1 + TheBank/BankWebApi/BankWebApi.csproj | 1 + .../Controllers/StorekeepersController.cs | 19 +- .../BankWebApi/Infrastructure/IJwtProvider.cs | 8 + .../BankWebApi/Infrastructure/JwtProvider.cs | 21 + .../Infrastructure/PasswordHelper.cs | 7 + TheBank/BankWebApi/Program.cs | 36 +- TheBank/bankui/bun.lockb | Bin 141538 -> 143170 bytes TheBank/bankui/package-lock.json | 3602 +++++++++++++++++ TheBank/bankui/package.json | 3 + TheBank/bankui/src/api/api.ts | 2 + TheBank/bankui/src/api/client.ts | 3 + .../src/components/features/LoginForm.tsx | 82 + .../src/components/features/RegisterForm.tsx | 166 + .../bankui/src/components/layout/Header.tsx | 2 +- .../src/components/pages/AuthStorekeeper.tsx | 50 + .../src/components/pages/CreditPrograms.tsx | 5 +- TheBank/bankui/src/components/ui/sonner.tsx | 23 + TheBank/bankui/src/components/ui/tabs.tsx | 64 + TheBank/bankui/src/hooks/useStorekeepers.ts | 23 +- TheBank/bankui/src/main.tsx | 5 + TheBank/bankui/src/types/types.ts | 5 + 46 files changed, 5779 insertions(+), 46 deletions(-) create mode 100644 TheBank/BankContracts/BindingModels/StorekeeperAuthBindingModel.cs create mode 100644 TheBank/BankDatabase/DesignTimeDbContextFactory.cs create mode 100644 TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs create mode 100644 TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs create mode 100644 TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs create mode 100644 TheBank/BankWebApi/Infrastructure/IJwtProvider.cs create mode 100644 TheBank/BankWebApi/Infrastructure/JwtProvider.cs create mode 100644 TheBank/BankWebApi/Infrastructure/PasswordHelper.cs create mode 100644 TheBank/bankui/package-lock.json create mode 100644 TheBank/bankui/src/components/features/LoginForm.tsx create mode 100644 TheBank/bankui/src/components/features/RegisterForm.tsx create mode 100644 TheBank/bankui/src/components/pages/AuthStorekeeper.tsx create mode 100644 TheBank/bankui/src/components/ui/sonner.tsx create mode 100644 TheBank/bankui/src/components/ui/tabs.tsx 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 8581920a0a9c4d9f85d5b7af02a023b46f66c28f..4884d45029f9bb6432afbbdc629955486b216085 100644 GIT binary patch delta 26363 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.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; +}