From 7e767541cf4c8e8e3bd96aa131d99aade6e516b3 Mon Sep 17 00:00:00 2001 From: slinky55 Date: Fri, 1 May 2026 19:48:34 -0500 Subject: [PATCH] more stuff --- ApplianceRepair.csproj | 4 + Components/Pages/Home.razor.css | 19 +- Components/Pages/admin/Admin.razor | 37 +- Components/Pages/admin/Admin.razor.cs | 88 +++- Components/Pages/admin/Admin.razor.css | 116 ++++- .../Pages/admin/Modal.razor | 0 .../20260424050555_InitialCreate.Designer.cs | 173 ------- Migrations/20260424050555_InitialCreate.cs | 125 ------ ...260502001727_InitialDeployment.Designer.cs | 421 ++++++++++++++++++ .../20260502001727_InitialDeployment.cs | 328 ++++++++++++++ Migrations/DatabaseContextModelSnapshot.cs | 248 +++++++++++ Models.cs | 12 + Program.cs | 10 +- Services.cs | 18 +- appsettings.json | 4 +- wwwroot/app.css | 8 + wwwroot/fonts/Stencil Std Bold.ttf | Bin 0 -> 24176 bytes wwwroot/uploads/uefue0ou.esy.png | Bin 4909 -> 0 bytes 18 files changed, 1292 insertions(+), 319 deletions(-) rename wwwroot/uploads/exvwoomm.qgm.jpg => Components/Pages/admin/Modal.razor (100%) delete mode 100644 Migrations/20260424050555_InitialCreate.Designer.cs delete mode 100644 Migrations/20260424050555_InitialCreate.cs create mode 100644 Migrations/20260502001727_InitialDeployment.Designer.cs create mode 100644 Migrations/20260502001727_InitialDeployment.cs create mode 100644 wwwroot/fonts/Stencil Std Bold.ttf delete mode 100644 wwwroot/uploads/uefue0ou.esy.png diff --git a/ApplianceRepair.csproj b/ApplianceRepair.csproj index 18175c8..6326251 100644 --- a/ApplianceRepair.csproj +++ b/ApplianceRepair.csproj @@ -22,4 +22,8 @@ + + + + diff --git a/Components/Pages/Home.razor.css b/Components/Pages/Home.razor.css index fee8b4d..71142d2 100644 --- a/Components/Pages/Home.razor.css +++ b/Components/Pages/Home.razor.css @@ -4,6 +4,7 @@ margin: 0; padding: 0; box-sizing: border-box; + font-family: 'StencilBold', sans-serif; } .container { @@ -31,7 +32,7 @@ .logo { font-size: 1.5rem; font-weight: bold; - color: #0056b3; + color: black; } .logo span { @@ -40,13 +41,13 @@ .nav-phone { text-decoration: none; - color: #0056b3; + color: black; font-weight: bold; } /* Hero Section */ .hero { - background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://images.unsplash.com/photo-1581092918056-0c4c3acd3789?auto=format&fit=crop&w=1200&q=80'); + background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://images.unsplash.com/photo-1588854337115-1c67d9247e4d?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'); background-size: cover; background-position: center; color: #fff; @@ -60,7 +61,7 @@ } .hero h1 span { - color: #4cc9f0; + color: #D2B48C; } /* Buttons */ @@ -111,22 +112,22 @@ padding: 30px; border-radius: 8px; text-align: center; - border-bottom: 4px solid #0056b3; + border-bottom: 4px solid #D2B48C; box-shadow: 0 4px 6px rgba(0,0,0,0.05); } /* Trust Section */ .trust { - background: #0056b3; + background: #D2B48C; color: #fff; padding: 40px 0; text-align: center; } .trust .container { -display: flex; -justify-content: space-around; -flex-wrap: wrap; + display: flex; + justify-content: space-around; + flex-wrap: wrap; } .trust-item { diff --git a/Components/Pages/admin/Admin.razor b/Components/Pages/admin/Admin.razor index fa664b1..5472383 100644 --- a/Components/Pages/admin/Admin.razor +++ b/Components/Pages/admin/Admin.razor @@ -2,6 +2,37 @@ @using Microsoft.AspNetCore.Authorization @attribute [Authorize(Roles = "Admin")] @rendermode InteractiveServer +@inject IJSRuntime JS + + + @if (SelectedRequestMedia?.Any() == true) + { +
+ Request: @SelectedRequestMedia[0].RequestNumber + +
+ } + + +
@@ -72,6 +103,7 @@ @foreach (var card in HomePageModel.ServicesCards) {
+
@@ -93,6 +125,7 @@ @foreach (var card in HomePageModel.TrustCards) {
+
@@ -146,6 +179,8 @@ } else if (CurrentTab == AdminTab.Requests) { + +

📋 Service Requests

@@ -187,7 +222,7 @@
- +
} diff --git a/Components/Pages/admin/Admin.razor.cs b/Components/Pages/admin/Admin.razor.cs index d21b581..1be3ab1 100644 --- a/Components/Pages/admin/Admin.razor.cs +++ b/Components/Pages/admin/Admin.razor.cs @@ -1,13 +1,17 @@ using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; namespace ApplianceRepair.Components.Pages.admin { - public partial class Admin(HomePageReader homePageReader, ContentCardReader contentCardReader, BusinessConfigReader businessConfigReader, RepairRequestReader repairRequestReader) : ComponentBase + public partial class Admin(HomePageReader homePageReader, ContentCardReader contentCardReader, BusinessConfigReader businessConfigReader, RepairRequestReader repairRequestReader, RepairRequestMediaReader repairRequestMediaReader) : ComponentBase { public HomePageModel? HomePageModel; public BusinessInfoModel? BusinessInfo; public List? RepairRequests; + public List? SelectedRequestMedia; + public int SelectedRequestMediaImageIndex = 0; + private enum AdminTab { Home, Requests, BusinessInfo } private AdminTab CurrentTab = AdminTab.Home; @@ -28,6 +32,29 @@ namespace ApplianceRepair.Components.Pages.admin }); } + private async void RefreshContentCards() + { + if (HomePageModel == null) + { + return; + } + + var servicesList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Services)) ?? []; + var trustList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Trust)) ?? []; + + HomePageModel.ServicesCards.Clear(); + foreach (var card in servicesList) + { + HomePageModel.ServicesCards.Add(new ContentCardModel(card)); + } + + HomePageModel.TrustCards.Clear(); + foreach (var card in trustList) + { + HomePageModel.TrustCards.Add(new ContentCardModel(card)); + } + } + private async void RevertHomePageModel() { var businessConfig = await businessConfigReader.ReadLatestRecord() ?? Defaults.DefaultBusinessConfig; @@ -69,6 +96,12 @@ namespace ApplianceRepair.Components.Pages.admin await businessConfigReader.UpdateRecord(BusinessInfo); } + private async Task DeleteContentCard(ContentCardModel card) + { + await contentCardReader.DeleteRecord(card); + RefreshContentCards(); + } + private void AddServiceCard() { HomePageModel?.ServicesCards.Add(new ContentCardModel() { @@ -93,5 +126,58 @@ namespace ApplianceRepair.Components.Pages.admin Text = "Short Description" }); } + + private async Task ViewRequestImages(RepairRequestModel request) + { + if (!string.IsNullOrEmpty(request.RequestNumber)) + { + SelectedRequestMedia = await repairRequestMediaReader.ReadAllByRequestNumber(request.RequestNumber); + SelectedRequestMediaImageIndex = 0; + await JS.InvokeVoidAsync("eval", $"document.getElementById('imageViewerModal').showModal()"); + } + } + + private async Task CloseImageViewer() + { + await JS.InvokeVoidAsync("eval", $"document.getElementById('imageViewerModal').close()"); + SelectedRequestMedia = []; + } + + private async Task ImageViewerModal_PrevImage() + { + if (SelectedRequestMedia == null) return; + + SelectedRequestMediaImageIndex++; + if (SelectedRequestMediaImageIndex >= SelectedRequestMedia.Count()) + { + SelectedRequestMediaImageIndex = 0; + } + } + + private async Task ImageViewerModal_NextImage() + { + if (SelectedRequestMedia == null) return; + SelectedRequestMediaImageIndex--; + if (SelectedRequestMediaImageIndex < 0) + { + SelectedRequestMediaImageIndex = SelectedRequestMedia.Count() - 1; + } + } + + private string GetWebPath(string fullPath = "") + { + if (string.IsNullOrEmpty(fullPath)) return ""; + + var marker = "wwwroot"; + var index = fullPath.IndexOf(marker); + + if (index != -1) + { + // Returns "/uploads/filename.jpg" + return fullPath.Substring(index + marker.Length).Replace('\\', '/'); + } + + return fullPath; + } } } diff --git a/Components/Pages/admin/Admin.razor.css b/Components/Pages/admin/Admin.razor.css index eddde49..486c4d0 100644 --- a/Components/Pages/admin/Admin.razor.css +++ b/Components/Pages/admin/Admin.razor.css @@ -5,6 +5,107 @@ font-family: 'Open Sans', sans-serif; } +/* Image Viewer Modal */ +.image-viewer-modal[open] { + border: none; + border-radius: 12px; + padding: 0; + max-width: 90vw; + width: 1000px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); + background-color: #fff; + overflow: hidden; +} + +.image-viewer-modal::backdrop { + background-color: rgba(0, 0, 0, 0.75); + backdrop-filter: blur(4px); +} + +.image-viewer-modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.5rem; + background-color: #f8f9fa; + border-bottom: 1px solid #e9ecef; + font-weight: 600; +} + +.image-viewer-image-stage { + flex-grow: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 400px; + max-height: 70vh; + background-color: #000; + border-radius: 8px; + position: relative; + overflow: hidden; +} + +.image-viewer-image-stage img { + max-width: 100%; + max-height: 100%; + object-fit: contain; + display: block; +} + +.image-viewer-carousel-container { + display: flex; + align-items: center; + padding: 1.5rem; + gap: 1rem; + background-color: #f1f3f5; +} + +.image-viewer-nav-btn { + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 50%; + width: 45px; + height: 45px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + font-size: 1.2rem; + transition: all 0.2s ease; + box-shadow: 0 4px 6px rgba(0,0,0,0.1); + z-index: 10; +} + +.image-viewer-nav-btn:hover { + background-color: #007bff; + color: white; + transform: scale(1.1); +} + +.image-viewer-nav-btn:active { + transform: scale(0.95); +} + +.image-viewer-image-counter { + position: absolute; + bottom: 10px; + background: rgba(0, 0, 0, 0.6); + color: white; + padding: 4px 12px; + border-radius: 20px; + font-size: 0.85rem; +} + +.image-viewer-no-images { + width: 100%; + text-align: center; + padding: 3rem; + color: #6c757d; + font-style: italic; +} +/* Image viewer modal */ + .admin-header { text-align: center; margin-bottom: 40px; @@ -109,12 +210,12 @@ label { border: 1px solid #e0e6ed; border-radius: 12px; padding: 20px; - transition: transform 0.2s ease; - display: flex; flex-direction: column; align-content: center; + + position: relative; } .content-card:hover { @@ -294,6 +395,17 @@ label { animation: fadeIn 0.5s ease; } +.close-btn { + position: absolute; + top: 5px; + right: 5px; + background: none; + border: none; + font-size: 20px; + cursor: pointer; + line-height: 1; +} + @keyframes fadeIn { from { opacity: 0; diff --git a/wwwroot/uploads/exvwoomm.qgm.jpg b/Components/Pages/admin/Modal.razor similarity index 100% rename from wwwroot/uploads/exvwoomm.qgm.jpg rename to Components/Pages/admin/Modal.razor diff --git a/Migrations/20260424050555_InitialCreate.Designer.cs b/Migrations/20260424050555_InitialCreate.Designer.cs deleted file mode 100644 index 7baa601..0000000 --- a/Migrations/20260424050555_InitialCreate.Designer.cs +++ /dev/null @@ -1,173 +0,0 @@ -// -using System; -using ApplianceRepair; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace ApplianceRepair.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20260424050555_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "9.0.12"); - - modelBuilder.Entity("ApplianceRepair.BusinessConfigRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CreatedAt") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("PhoneNumber") - .HasColumnType("TEXT"); - - b.Property("SupportEmail") - .HasColumnType("TEXT"); - - b.Property("UpdatedAt") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("BusinessConfig"); - }); - - modelBuilder.Entity("ApplianceRepair.ContentCardRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("BelongsToPage") - .HasColumnType("TEXT"); - - b.Property("CreatedAt") - .HasColumnType("TEXT"); - - b.Property("Group") - .HasColumnType("TEXT"); - - b.Property("Header") - .HasColumnType("TEXT"); - - b.Property("Text") - .HasColumnType("TEXT"); - - b.Property("UpdatedAt") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ContentCards"); - }); - - modelBuilder.Entity("ApplianceRepair.HomePageRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("BookHeaderText") - .HasColumnType("TEXT"); - - b.Property("CallHeaderText") - .HasColumnType("TEXT"); - - b.Property("CreatedAt") - .HasColumnType("TEXT"); - - b.Property("HeaderLine1") - .HasColumnType("TEXT"); - - b.Property("HeaderLine2") - .HasColumnType("TEXT"); - - b.Property("HeaderText") - .HasColumnType("TEXT"); - - b.Property("SecondaryHeaderText") - .HasColumnType("TEXT"); - - b.Property("UpdatedAt") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("HomePage"); - }); - - modelBuilder.Entity("ApplianceRepair.RepairRequestMediaRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("CreatedAt") - .HasColumnType("TEXT"); - - b.Property("MediaPath") - .HasColumnType("TEXT"); - - b.Property("RequestNumber") - .HasColumnType("TEXT"); - - b.Property("UpdatedAt") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("RepairRequestMedia"); - }); - - modelBuilder.Entity("ApplianceRepair.RepairRequestRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Brand") - .HasColumnType("TEXT"); - - b.Property("CreatedAt") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Notes") - .HasColumnType("TEXT"); - - b.Property("Phone") - .HasColumnType("TEXT"); - - b.Property("RequestNumber") - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("TEXT"); - - b.Property("UpdatedAt") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("RepairRequests"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Migrations/20260424050555_InitialCreate.cs b/Migrations/20260424050555_InitialCreate.cs deleted file mode 100644 index 40d9bb7..0000000 --- a/Migrations/20260424050555_InitialCreate.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ApplianceRepair.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "BusinessConfig", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatedAt = table.Column(type: "TEXT", nullable: false), - UpdatedAt = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", nullable: true), - PhoneNumber = table.Column(type: "TEXT", nullable: true), - SupportEmail = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BusinessConfig", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "ContentCards", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatedAt = table.Column(type: "TEXT", nullable: false), - UpdatedAt = table.Column(type: "TEXT", nullable: false), - BelongsToPage = table.Column(type: "TEXT", nullable: true), - Group = table.Column(type: "TEXT", nullable: true), - Header = table.Column(type: "TEXT", nullable: true), - Text = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ContentCards", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "HomePage", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatedAt = table.Column(type: "TEXT", nullable: false), - UpdatedAt = table.Column(type: "TEXT", nullable: false), - HeaderLine1 = table.Column(type: "TEXT", nullable: true), - HeaderLine2 = table.Column(type: "TEXT", nullable: true), - HeaderText = table.Column(type: "TEXT", nullable: true), - CallHeaderText = table.Column(type: "TEXT", nullable: true), - BookHeaderText = table.Column(type: "TEXT", nullable: true), - SecondaryHeaderText = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_HomePage", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "RepairRequestMedia", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatedAt = table.Column(type: "TEXT", nullable: false), - UpdatedAt = table.Column(type: "TEXT", nullable: false), - RequestNumber = table.Column(type: "TEXT", nullable: true), - MediaPath = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_RepairRequestMedia", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "RepairRequests", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatedAt = table.Column(type: "TEXT", nullable: false), - UpdatedAt = table.Column(type: "TEXT", nullable: false), - RequestNumber = table.Column(type: "TEXT", nullable: true), - Type = table.Column(type: "TEXT", nullable: true), - Brand = table.Column(type: "TEXT", nullable: true), - Notes = table.Column(type: "TEXT", nullable: true), - Name = table.Column(type: "TEXT", nullable: true), - Phone = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_RepairRequests", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "BusinessConfig"); - - migrationBuilder.DropTable( - name: "ContentCards"); - - migrationBuilder.DropTable( - name: "HomePage"); - - migrationBuilder.DropTable( - name: "RepairRequestMedia"); - - migrationBuilder.DropTable( - name: "RepairRequests"); - } - } -} diff --git a/Migrations/20260502001727_InitialDeployment.Designer.cs b/Migrations/20260502001727_InitialDeployment.Designer.cs new file mode 100644 index 0000000..c15aec2 --- /dev/null +++ b/Migrations/20260502001727_InitialDeployment.Designer.cs @@ -0,0 +1,421 @@ +// +using System; +using ApplianceRepair; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ApplianceRepair.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20260502001727_InitialDeployment")] + partial class InitialDeployment + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.12"); + + modelBuilder.Entity("ApplianceRepair.BusinessConfigRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("SupportEmail") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BusinessConfig"); + }); + + modelBuilder.Entity("ApplianceRepair.ContentCardRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BelongsToPage") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasColumnType("TEXT"); + + b.Property("Header") + .HasColumnType("TEXT"); + + b.Property("Text") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ContentCards"); + }); + + modelBuilder.Entity("ApplianceRepair.HomePageRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BookHeaderText") + .HasColumnType("TEXT"); + + b.Property("CallHeaderText") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("HeaderLine1") + .HasColumnType("TEXT"); + + b.Property("HeaderLine2") + .HasColumnType("TEXT"); + + b.Property("HeaderText") + .HasColumnType("TEXT"); + + b.Property("SecondaryHeaderText") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HomePage"); + }); + + modelBuilder.Entity("ApplianceRepair.RepairRequestMediaRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("MediaPath") + .HasColumnType("TEXT"); + + b.Property("RequestNumber") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RepairRequestMedia"); + }); + + modelBuilder.Entity("ApplianceRepair.RepairRequestRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Brand") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Notes") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Phone") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RequestNumber") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RepairRequests"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260502001727_InitialDeployment.cs b/Migrations/20260502001727_InitialDeployment.cs new file mode 100644 index 0000000..3c10dda --- /dev/null +++ b/Migrations/20260502001727_InitialDeployment.cs @@ -0,0 +1,328 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ApplianceRepair.Migrations +{ + /// + public partial class InitialDeployment : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "INTEGER", nullable: false), + PasswordHash = table.Column(type: "TEXT", nullable: true), + SecurityStamp = table.Column(type: "TEXT", nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + LockoutEnd = table.Column(type: "TEXT", nullable: true), + LockoutEnabled = table.Column(type: "INTEGER", nullable: false), + AccessFailedCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "BusinessConfig", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + SupportEmail = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BusinessConfig", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ContentCards", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false), + BelongsToPage = table.Column(type: "TEXT", nullable: true), + Group = table.Column(type: "TEXT", nullable: true), + Header = table.Column(type: "TEXT", nullable: true), + Text = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ContentCards", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "HomePage", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false), + HeaderLine1 = table.Column(type: "TEXT", nullable: true), + HeaderLine2 = table.Column(type: "TEXT", nullable: true), + HeaderText = table.Column(type: "TEXT", nullable: true), + CallHeaderText = table.Column(type: "TEXT", nullable: true), + BookHeaderText = table.Column(type: "TEXT", nullable: true), + SecondaryHeaderText = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_HomePage", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "RepairRequestMedia", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false), + RequestNumber = table.Column(type: "TEXT", nullable: true), + MediaPath = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RepairRequestMedia", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "RepairRequests", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false), + RequestNumber = table.Column(type: "TEXT", nullable: true), + Type = table.Column(type: "TEXT", nullable: false), + Brand = table.Column(type: "TEXT", nullable: false), + Notes = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Phone = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RepairRequests", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RoleId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "TEXT", nullable: false), + ProviderKey = table.Column(type: "TEXT", nullable: false), + ProviderDisplayName = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + RoleId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + LoginProvider = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "BusinessConfig"); + + migrationBuilder.DropTable( + name: "ContentCards"); + + migrationBuilder.DropTable( + name: "HomePage"); + + migrationBuilder.DropTable( + name: "RepairRequestMedia"); + + migrationBuilder.DropTable( + name: "RepairRequests"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/Migrations/DatabaseContextModelSnapshot.cs b/Migrations/DatabaseContextModelSnapshot.cs index a642903..549d731 100644 --- a/Migrations/DatabaseContextModelSnapshot.cs +++ b/Migrations/DatabaseContextModelSnapshot.cs @@ -137,24 +137,29 @@ namespace ApplianceRepair.Migrations .HasColumnType("INTEGER"); b.Property("Brand") + .IsRequired() .HasColumnType("TEXT"); b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("Name") + .IsRequired() .HasColumnType("TEXT"); b.Property("Notes") + .IsRequired() .HasColumnType("TEXT"); b.Property("Phone") + .IsRequired() .HasColumnType("TEXT"); b.Property("RequestNumber") .HasColumnType("TEXT"); b.Property("Type") + .IsRequired() .HasColumnType("TEXT"); b.Property("UpdatedAt") @@ -164,6 +169,249 @@ namespace ApplianceRepair.Migrations b.ToTable("RepairRequests"); }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); #pragma warning restore 612, 618 } } diff --git a/Models.cs b/Models.cs index 1d67b32..ef4621f 100644 --- a/Models.cs +++ b/Models.cs @@ -12,6 +12,9 @@ public ContentCardModel(ContentCardRecord record) { + Id = record.Id; + CreatedAt = record.CreatedAt; + UpdatedAt = record.UpdatedAt; BelongsToPage = record.BelongsToPage; Group = record.Group; Header = record.Header; @@ -98,6 +101,9 @@ List serviceCards, List trustCards) { + Id = homePageRecord.Id; + CreatedAt = homePageRecord.CreatedAt; + UpdatedAt = homePageRecord.UpdatedAt; HeaderLine1 = homePageRecord.HeaderLine1; HeaderLine2 = homePageRecord.HeaderLine2; HeaderText = homePageRecord.HeaderText; @@ -155,6 +161,9 @@ public RepairRequestModel(RepairRequestRecord record) { + Id = record.Id; + CreatedAt = record.CreatedAt; + UpdatedAt = record.UpdatedAt; RequestNumber = record.RequestNumber; Type = record.Type; Brand = record.Brand; @@ -168,6 +177,9 @@ { public BusinessInfoModel(BusinessConfigRecord record) { + Id = record.Id; + CreatedAt = record.CreatedAt; + UpdatedAt = record.UpdatedAt; Name = record.Name; PhoneNumber = record.PhoneNumber; SupportEmail = record.SupportEmail; diff --git a/Program.cs b/Program.cs index 2077491..522f074 100644 --- a/Program.cs +++ b/Program.cs @@ -6,14 +6,14 @@ using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; var builder = WebApplication.CreateBuilder(args); -var connectionString = builder.Configuration.GetConnectionString("DatabaseContextConnectionString") ?? throw new InvalidOperationException("Connection string 'DatabaseContextConnectionString' not found."); +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); builder.Services.AddDbContext(options => - options.UseSqlite("Data Source=site.db")); + options.UseSqlite(connectionString)); builder.Services.AddMemoryCache(); builder.Services.AddLogging(); @@ -45,6 +45,12 @@ builder.Services.AddIdentityCore(options => options.SignIn.Require .AddSignInManager() .AddDefaultTokenProviders(); +builder.Services.AddServerSideBlazor() + .AddHubOptions(options => + { + options.MaximumReceiveMessageSize = 10 * 1024 * 1024; // 10MB + }); + builder.Services.AddSingleton, IdentityNoOpEmailSender>(); var app = builder.Build(); diff --git a/Services.cs b/Services.cs index eb7bf8f..2f4b603 100644 --- a/Services.cs +++ b/Services.cs @@ -27,7 +27,7 @@ namespace ApplianceRepair } else { - db.HomePage.Update(record); + db.Entry(found).CurrentValues.SetValues(record); } await db.SaveChangesAsync(); } @@ -60,10 +60,20 @@ namespace ApplianceRepair } else { - db.ContentCards.Update(record); + db.Entry(found).CurrentValues.SetValues(record); } await db.SaveChangesAsync(); } + + public async Task DeleteRecord(ContentCardRecord record) + { + var found = db.ContentCards.Where((card) => card.Id == record.Id).FirstOrDefault(); + if (found != null) + { + db.ContentCards.Remove(found); + await db.SaveChangesAsync(); + } + } } public class BusinessConfigReader(DatabaseContext db) @@ -88,7 +98,7 @@ namespace ApplianceRepair } else { - db.BusinessConfig.Update(record); + db.Entry(found).CurrentValues.SetValues(record); } await db.SaveChangesAsync(); } @@ -121,7 +131,7 @@ namespace ApplianceRepair } else { - db.RepairRequests.Update(record); + db.Entry(found).CurrentValues.SetValues(record); } await db.SaveChangesAsync(); } diff --git a/appsettings.json b/appsettings.json index b7a4f8c..8abf816 100644 --- a/appsettings.json +++ b/appsettings.json @@ -7,7 +7,7 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DatabaseContextConnectionString": "Data Source=site.db" + "DefaultConnection": "Data Source=/var/www/site_data/site.db" }, - "SiteDomain": "titanappliancerepair.net" + "SiteDomain": "yoursitename.net" } \ No newline at end of file diff --git a/wwwroot/app.css b/wwwroot/app.css index f9c1cfc..3a3849c 100644 --- a/wwwroot/app.css +++ b/wwwroot/app.css @@ -1,5 +1,13 @@ @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@600;700&family=Open+Sans:wght@400;600&display=swap'); +@font-face { + font-family: 'StencilBold'; + src: url('fonts/Stencil Std Bold.ttf') format('truetype'); + font-weight: Bold; + font-style: normal; + font-display: swap; +} + h1:focus { outline: none; } diff --git a/wwwroot/fonts/Stencil Std Bold.ttf b/wwwroot/fonts/Stencil Std Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3b7fb96e060498ca14993383f3030e4ad7afdf1e GIT binary patch literal 24176 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 Wt-gslH0X=!xwlpF&oRC8JpTqQyY;sK literal 0 HcmV?d00001 diff --git a/wwwroot/uploads/uefue0ou.esy.png b/wwwroot/uploads/uefue0ou.esy.png deleted file mode 100644 index bfb0ff723c71e0a16822cf73b5ff02d74dfb0405..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4909 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