bunch o stuff
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
@page "/book"
|
||||
@rendermode InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
|
||||
<div class="container booking-page">
|
||||
@if(!Complete)
|
||||
{
|
||||
<div class="container booking-page">
|
||||
<div class="section-title">
|
||||
<h1>Request an Appointment</h1>
|
||||
<p>Complete the form below and a technician will review your case.</p>
|
||||
</div>
|
||||
|
||||
<EditForm Model="@Model" OnValidSubmit="HandleSubmit" class="booking-form-wrapper">
|
||||
<EditForm FormName="RepairRequestForm" Model="Model" OnValidSubmit="HandleSubmit" On class="booking-form-wrapper">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<div class="form-grid">
|
||||
@@ -24,6 +27,7 @@
|
||||
<option>Oven / Stove</option>
|
||||
<option>Dryer</option>
|
||||
</InputSelect>
|
||||
<ValidationMessage For="@(() => Model.Type)" class="text-danger" />
|
||||
</div>
|
||||
|
||||
<div class="field-group">
|
||||
@@ -42,6 +46,7 @@
|
||||
<option>Kenmore</option>
|
||||
<option>Other (please include in notes)</option>
|
||||
</InputSelect>
|
||||
<ValidationMessage For="@(() => Model.Brand)" class="text-danger" />
|
||||
</div>
|
||||
|
||||
<div class="field-group">
|
||||
@@ -49,6 +54,7 @@
|
||||
<InputTextArea @bind-Value="Model.Notes"
|
||||
placeholder="e.g. Making a clicking noise, not draining, error code F1E2..."
|
||||
class="custom-input textarea" />
|
||||
<ValidationMessage For="@(() => Model.Notes)" class="text-danger" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +62,7 @@
|
||||
<h3 class="form-heading">2. Photos & Contact</h3>
|
||||
|
||||
<div class="upload-zone">
|
||||
<p><strong>Upload Photos/Video</strong></p>
|
||||
<p><strong>Upload Photos/Video (10MB max)</strong></p>
|
||||
<p class="small-text">Tip: A photo of the <u>model number sticker</u> helps us arrive with the right parts!</p>
|
||||
<InputFile OnChange="HandleFiles" multiple class="file-input" id="file-upload" />
|
||||
<label for="file-upload" class="btn btn-secondary">Add Media</label>
|
||||
@@ -70,11 +76,13 @@
|
||||
<div class="field-group">
|
||||
<label>Full Name</label>
|
||||
<InputText @bind-Value="Model.Name" class="custom-input" />
|
||||
<ValidationMessage For="@(() => Model.Name)" class="text-danger" />
|
||||
</div>
|
||||
|
||||
<div class="field-group">
|
||||
<label>Phone Number</label>
|
||||
<InputText @bind-Value="Model.Phone" class="custom-input" />
|
||||
<ValidationMessage For="@(() => Model.Phone)" class="text-danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,4 +91,18 @@
|
||||
<button type="submit" class="btn btn-primary btn-large">Submit Repair Request</button>
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="complete-container">
|
||||
<div class="complete-content">
|
||||
<h1 class="complete-heading">Thank You!</h1>
|
||||
<p class="complete-subheading">We will be contacting you shortly.</p>
|
||||
<p class="complete-subheading">Your request number is: @Model.RequestNumber</p>
|
||||
<NavLink class="btn-home" href="" Match="NavLinkMatch.All">
|
||||
<span class="home-icon">🏠</span> Back to Home
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -2,16 +2,70 @@
|
||||
|
||||
namespace ApplianceRepair.Components.Pages
|
||||
{
|
||||
public partial class Book()
|
||||
public static class RequestNumberGenerator
|
||||
{
|
||||
private RepairRequestModel Model = new();
|
||||
private List<IBrowserFile> SelectedFiles = new();
|
||||
private static readonly char[] _chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789".ToCharArray();
|
||||
|
||||
public static string Generate(int length = 6)
|
||||
{
|
||||
var result = new char[length];
|
||||
// Use Random.Shared in .NET 6+ for thread safety
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result[i] = _chars[Random.Shared.Next(_chars.Length)];
|
||||
}
|
||||
return new string(result);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Book(RepairRequestReader repairRequestReader, RepairRequestMediaReader repairRequestMediaReader)
|
||||
{
|
||||
public RepairRequestModel Model = new();
|
||||
public List<IBrowserFile> SelectedFiles = new();
|
||||
public bool Complete = false;
|
||||
|
||||
private void HandleFiles(InputFileChangeEventArgs e) => SelectedFiles.AddRange(e.GetMultipleFiles());
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
// Logic to process the request
|
||||
Model.RequestNumber = RequestNumberGenerator.Generate();
|
||||
Model.CreatedAt = DateTime.Now;
|
||||
Model.UpdatedAt = DateTime.Now;
|
||||
await repairRequestReader.AddRecord(Model);
|
||||
|
||||
var imageUploadPath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "uploads");
|
||||
if (!Directory.Exists(imageUploadPath)) Directory.CreateDirectory(imageUploadPath);
|
||||
|
||||
foreach (var file in SelectedFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var trustedFileName = Path.GetRandomFileName() + Path.GetExtension(file.Name);
|
||||
var path = Path.Combine(imageUploadPath, trustedFileName);
|
||||
|
||||
using var stream = file.OpenReadStream(maxAllowedSize: 1024 * 1024 * 10);
|
||||
using var fileStream = new FileStream(path, FileMode.Create);
|
||||
|
||||
await stream.CopyToAsync(fileStream);
|
||||
|
||||
var mediaRecord = new RepairRequestMediaRecord()
|
||||
{
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now,
|
||||
RequestNumber = Model.RequestNumber,
|
||||
MediaPath = path,
|
||||
};
|
||||
|
||||
await repairRequestMediaReader.AddRecord(mediaRecord);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// probably need to show this to the user somehow, something prettier tho
|
||||
Console.WriteLine($"File: {file.Name} Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
Complete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,61 @@
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Match your mobile responsiveness */
|
||||
.complete-container {
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.complete-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.complete-heading {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.complete-subheading {
|
||||
font-size: 1.2rem;
|
||||
color: #555;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
::deep .btn-home {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 24px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease, transform 0.1s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::deep .btn-home:hover {
|
||||
background-color: #0056b3;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
::deep .btn-home:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.home-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -102,4 +156,12 @@
|
||||
.booking-form-wrapper {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.complete-heading {
|
||||
font-size: 1.8rem; /* Slightly smaller for small screens */
|
||||
}
|
||||
|
||||
.complete-subheading {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace ApplianceRepair.Components.Pages
|
||||
{
|
||||
public partial class Home(IMemoryCache cache, HomePageReader homePageReader, ContentCardReader contentCardReader)
|
||||
public partial class Home(IMemoryCache cache, HomePageReader homePageReader, ContentCardReader contentCardReader, BusinessConfigReader businessConfigReader)
|
||||
{
|
||||
private HomePageModel? Model;
|
||||
|
||||
@@ -10,7 +10,12 @@ namespace ApplianceRepair.Components.Pages
|
||||
{
|
||||
if (!cache.TryGetValue(nameof(HomePageModel), out Model))
|
||||
{
|
||||
Model = await homePageReader.ReadLatestRecordWithModel(contentCardReader) ?? Defaults.DefaultHomePageContent;
|
||||
var businessConfig = await businessConfigReader.ReadLatestRecord() ?? Defaults.DefaultBusinessConfig;
|
||||
var latestHomeRecord = await homePageReader.ReadLatestRecord() ?? Defaults.DefaultHomePageContent;
|
||||
var servicesList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Services)) ?? [];
|
||||
var trustList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Trust)) ?? [];
|
||||
|
||||
Model = new HomePageModel(latestHomeRecord, businessConfig, servicesList, trustList);
|
||||
|
||||
var cacheOptions = new MemoryCacheEntryOptions()
|
||||
.SetAbsoluteExpiration(TimeSpan.FromHours(24))
|
||||
|
||||
@@ -21,7 +21,7 @@ else
|
||||
<h1>@Model.HeaderLine1 <br><span>@Model.HeaderLine2</span></h1>
|
||||
<p>@Model.HeaderText</p>
|
||||
<div class="cta-group">
|
||||
<a href="phone:@Model.FormattedPhoneNumber" class="btn btn-primary">Call for Same-Day Service</a>
|
||||
<a href="@Model.PhoneNumberCallLink" class="btn btn-primary">Call for Same-Day Service</a>
|
||||
<a href="/book" class="btn btn-secondary">Request an Appointment</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,16 +21,22 @@
|
||||
<div class="container">
|
||||
<header class="admin-header">
|
||||
<div class="tab-container">
|
||||
<button class="tab-btn @(currentTab == AdminTab.Home ? "active" : "")"
|
||||
@onclick="() => currentTab = AdminTab.Home">
|
||||
<button class="tab-btn @(CurrentTab == AdminTab.Home ? "active" : "")"
|
||||
@onclick="() => CurrentTab = AdminTab.Home">
|
||||
Home Page
|
||||
</button>
|
||||
</div>
|
||||
<div class="tab-container">
|
||||
<button class="tab-btn @(CurrentTab == AdminTab.BusinessInfo ? "active" : "")"
|
||||
@onclick="() => CurrentTab = AdminTab.BusinessInfo">
|
||||
Business Info
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@if (currentTab == AdminTab.Home)
|
||||
@if (CurrentTab == AdminTab.Home)
|
||||
{
|
||||
<EditForm FormName="HomePageForm" Model="HomePageModel" OnValidSubmit="SaveHomePageModel" On class="admin-form home-page-form">
|
||||
<EditForm FormName="HomePageForm" Model="HomePageModel" OnValidSubmit="SaveHomePageModel" On class="admin-form">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<div class="form-section text-center">
|
||||
@@ -100,9 +106,35 @@
|
||||
</div>
|
||||
</EditForm>
|
||||
}
|
||||
else
|
||||
else if (CurrentTab == AdminTab.BusinessInfo)
|
||||
{
|
||||
<h1>Another page</h1>
|
||||
<EditForm FormName="BusinessInfoForm" Model="BusinessInfo" OnValidSubmit="SaveBusinessInfo" On class="admin-form">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<div class="form-section text-center">
|
||||
<h3><i class="icon">🏠</i> Business Info</h3>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Business Name</label>
|
||||
<InputText @bind-Value="BusinessInfo.Name" class="form-input" />
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Phone Number</label>
|
||||
<InputText @bind-Value="BusinessInfo.PhoneNumber" class="form-input" />
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Support Email</label>
|
||||
<InputText @bind-Value="BusinessInfo.SupportEmail" class="form-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-footer">
|
||||
<button type="submit" class="btn btn-save">Save</button>
|
||||
<button type="button" class="btn btn-revert" @onclick="RevertBusinessInfo">Revert</button>
|
||||
</div>
|
||||
</EditForm>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,39 +1,63 @@
|
||||
namespace ApplianceRepair.Components.Pages.admin
|
||||
{
|
||||
public partial class EditPages(HomePageReader homePageReader, ContentCardReader contentCardReader)
|
||||
public partial class EditPages(HomePageReader homePageReader, ContentCardReader contentCardReader, BusinessConfigReader businessConfigReader)
|
||||
{
|
||||
public HomePageModel? HomePageModel;
|
||||
public BusinessInfoModel? BusinessInfo;
|
||||
|
||||
private enum AdminTab { Home, About }
|
||||
private AdminTab currentTab = AdminTab.Home;
|
||||
private enum AdminTab { Home, About, BusinessInfo }
|
||||
private AdminTab CurrentTab = AdminTab.Home;
|
||||
|
||||
override
|
||||
protected async void OnInitialized()
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
HomePageModel = await homePageReader.ReadLatestRecordWithModel(contentCardReader) ?? Defaults.DefaultHomePageContent;
|
||||
var businessConfig = await businessConfigReader.ReadLatestRecord() ?? Defaults.DefaultBusinessConfig;
|
||||
var latestHomeRecord = await homePageReader.ReadLatestRecord() ?? Defaults.DefaultHomePageContent;
|
||||
var servicesList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Services)) ?? [];
|
||||
var trustList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Trust)) ?? [];
|
||||
|
||||
BusinessInfo = new BusinessInfoModel(businessConfig);
|
||||
HomePageModel = new HomePageModel(latestHomeRecord, businessConfig, servicesList, trustList);
|
||||
}
|
||||
|
||||
private async void RevertHomePageModel()
|
||||
{
|
||||
HomePageModel = await homePageReader.ReadLatestRecordWithModel(contentCardReader) ?? Defaults.DefaultHomePageContent;
|
||||
var businessConfig = await businessConfigReader.ReadLatestRecord() ?? Defaults.DefaultBusinessConfig;
|
||||
var latestHomeRecord = await homePageReader.ReadLatestRecord() ?? Defaults.DefaultHomePageContent;
|
||||
var servicesList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Services)) ?? [];
|
||||
var trustList = await contentCardReader.ReadAllByPageAndGroup(HomePageModel.PageName, nameof(HomePageModel.ContentCardTypes.Trust)) ?? [];
|
||||
|
||||
BusinessInfo = new BusinessInfoModel(businessConfig);
|
||||
HomePageModel = new HomePageModel(latestHomeRecord, businessConfig, servicesList, trustList);
|
||||
}
|
||||
|
||||
private async void RevertBusinessInfo()
|
||||
{
|
||||
var businessConfig = await businessConfigReader.ReadLatestRecord() ?? Defaults.DefaultBusinessConfig;
|
||||
BusinessInfo = new BusinessInfoModel(businessConfig);
|
||||
}
|
||||
|
||||
private async void SaveHomePageModel()
|
||||
{
|
||||
HomePageModel.CreatedAt = DateTime.Now;
|
||||
HomePageModel.UpdatedAt = DateTime.Now;
|
||||
await homePageReader.UpdateRecord(HomePageModel);
|
||||
|
||||
foreach (var card in HomePageModel.ServicesCards)
|
||||
{
|
||||
card.UpdatedAt = DateTime.Now;
|
||||
await contentCardReader.UpdateRecord(card);
|
||||
}
|
||||
|
||||
foreach (var card in HomePageModel.TrustCards)
|
||||
{
|
||||
card.UpdatedAt = DateTime.Now;
|
||||
await contentCardReader.UpdateRecord(card);
|
||||
}
|
||||
}
|
||||
|
||||
await homePageReader.AddRecord(HomePageModel);
|
||||
private async void SaveBusinessInfo()
|
||||
{
|
||||
BusinessInfo.UpdatedAt = DateTime.Now;
|
||||
await businessConfigReader.UpdateRecord(BusinessInfo);
|
||||
}
|
||||
|
||||
private void AddServiceCard()
|
||||
@@ -42,7 +66,7 @@
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now,
|
||||
BelongsToPage = HomePageModel.PageName,
|
||||
Group = HomePageModel.ContentCardTypes.Service.ToString(),
|
||||
Group = HomePageModel.ContentCardTypes.Services.ToString(),
|
||||
Header = "Service Name",
|
||||
Text = "Short Description"
|
||||
});
|
||||
|
||||
39
Data.cs
39
Data.cs
@@ -1,4 +1,6 @@
|
||||
namespace ApplianceRepair
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ApplianceRepair
|
||||
{
|
||||
public class HomePageRecord
|
||||
{
|
||||
@@ -11,15 +13,10 @@
|
||||
|
||||
public string? HeaderText { get; set; }
|
||||
|
||||
public string? HeaderButton1Text { get; set; }
|
||||
public string? HeaderButton2Text { get; set; }
|
||||
|
||||
public string? HeaderButton1Link { get; set; }
|
||||
public string? HeaderButton2Link { get; set; }
|
||||
public string? CallHeaderText { get; set; }
|
||||
public string? BookHeaderText { get; set; }
|
||||
|
||||
public string? SecondaryHeaderText { get; set; }
|
||||
|
||||
public string? CopyrightText { get; set; }
|
||||
}
|
||||
|
||||
public class ContentCardRecord
|
||||
@@ -47,10 +44,36 @@
|
||||
|
||||
public class RepairRequestRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
|
||||
public string? RequestNumber { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Appliance Type is required.")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Appliance brand is required.")]
|
||||
public string? Brand { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Description is required.")]
|
||||
public string? Notes { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Full Name is required.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Phone number is required.")]
|
||||
[Phone(ErrorMessage = "Please enter a valid phone number.")]
|
||||
public string? Phone { get; set; }
|
||||
}
|
||||
|
||||
public class RepairRequestMediaRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
|
||||
public string? RequestNumber { get; set; }
|
||||
public string? MediaPath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,47 @@ namespace ApplianceRepair
|
||||
public DbSet<ContentCardRecord> ContentCards { get; set; }
|
||||
public DbSet<BusinessConfigRecord> BusinessConfig { get; set; }
|
||||
public DbSet<RepairRequestRecord> RepairRequests { get; set; }
|
||||
public DbSet<RepairRequestMediaRecord> RepairRequestMedia { get; set; }
|
||||
|
||||
// Seed the data
|
||||
public static async Task Initialize(DatabaseContext context)
|
||||
{
|
||||
if (!context.BusinessConfig.Any())
|
||||
{
|
||||
var config = Defaults.DefaultBusinessConfig;
|
||||
config.CreatedAt = DateTime.Now;
|
||||
config.UpdatedAt = DateTime.Now;
|
||||
await context.BusinessConfig.AddAsync(config);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (!context.HomePage.Any())
|
||||
{
|
||||
var home = Defaults.DefaultHomePageContent;
|
||||
home.CreatedAt = DateTime.Now;
|
||||
home.UpdatedAt = DateTime.Now;
|
||||
await context.HomePage.AddAsync(home);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
if (!context.ContentCards.Any())
|
||||
{
|
||||
foreach (var card in Defaults.DefaultHomePageServiceCards)
|
||||
{
|
||||
card.CreatedAt = DateTime.Now;
|
||||
card.UpdatedAt = DateTime.Now;
|
||||
await context.ContentCards.AddAsync(card);
|
||||
}
|
||||
|
||||
foreach (var card in Defaults.DefaultHomePageTrustCards)
|
||||
{
|
||||
card.CreatedAt = DateTime.Now;
|
||||
card.UpdatedAt = DateTime.Now;
|
||||
await context.ContentCards.AddAsync(card);
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
Defaults.cs
41
Defaults.cs
@@ -2,39 +2,36 @@
|
||||
{
|
||||
public static class Defaults
|
||||
{
|
||||
public static readonly HomePageModel DefaultHomePageContent = new()
|
||||
public static readonly HomePageRecord DefaultHomePageContent = new()
|
||||
{
|
||||
BusinessName = "Appliance Pro",
|
||||
FormattedPhoneNumber = "(555) 012-3456",
|
||||
PhoneNumberCallLink = "tel:5550123456",
|
||||
|
||||
HeaderLine1 = "Expert Appliance Repair,",
|
||||
HeaderLine2 = "Done Right Today.",
|
||||
|
||||
HeaderText = "Fast, affordable repairs for all major brands. Serving the Greater Metro Area.",
|
||||
|
||||
HeaderButton1Text = "Call for Same-Day Service",
|
||||
HeaderButton1Link = "tel:5550123456",
|
||||
HeaderButton2Text = "Book Online",
|
||||
HeaderButton2Link = "#booking",
|
||||
CallHeaderText = "Call for Same-Day Service",
|
||||
BookHeaderText = "Book Online",
|
||||
|
||||
SecondaryHeaderText = "What We Fix",
|
||||
};
|
||||
|
||||
ServicesCards =
|
||||
[
|
||||
new() { Header = "Refrigerators", Text = "Cooling issues, leaks, and compressor repairs." },
|
||||
new() { Header = "Washers & Dryers", Text = "Fixing drum issues, drainage, and heating elements." },
|
||||
new() { Header = "Ovens & Ranges", Text = "Electrical igniters, gas flow, and temperature control." }
|
||||
],
|
||||
public static readonly List<ContentCardRecord> DefaultHomePageServiceCards = [
|
||||
new() { Header = "Refrigerators", Text = "Cooling issues, leaks, and compressor repairs.", BelongsToPage = "Home", Group = "Services" },
|
||||
new() { Header = "Washers & Dryers", Text = "Fixing drum issues, drainage, and heating elements.", BelongsToPage = "Home", Group = "Services" },
|
||||
new() { Header = "Ovens & Ranges", Text = "Electrical igniters, gas flow, and temperature control.", BelongsToPage = "Home", Group = "Services" }
|
||||
];
|
||||
|
||||
TrustCards =
|
||||
[
|
||||
new() { Header = "90-Day Warranty", Text = "Quality parts and labor guaranteed." },
|
||||
new() { Header = "Certified Techs", Text = "Licensed, bonded, and background-checked." },
|
||||
new() { Header = "Fair Pricing", Text = "No hidden fees or diagnostic surprises." }
|
||||
],
|
||||
public static readonly List<ContentCardRecord> DefaultHomePageTrustCards = [
|
||||
new() { Header = "90-Day Warranty", Text = "Quality parts and labor guaranteed.", BelongsToPage = "Home", Group = "Trust" },
|
||||
new() { Header = "Certified Techs", Text = "Licensed, bonded, and background-checked.", BelongsToPage = "Home", Group = "Trust" },
|
||||
new() { Header = "Fair Pricing", Text = "No hidden fees or diagnostic surprises.", BelongsToPage = "Home", Group = "Trust" }
|
||||
];
|
||||
|
||||
CopyrightText = $"© {DateTime.Now.Year} Appliance Pro. All rights reserved."
|
||||
public static readonly BusinessConfigRecord DefaultBusinessConfig = new()
|
||||
{
|
||||
Name = "Appliance Pro",
|
||||
PhoneNumber = "5550123456",
|
||||
SupportEmail = "appliance@pro.net"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
173
Migrations/20260424050555_InitialCreate.Designer.cs
generated
Normal file
173
Migrations/20260424050555_InitialCreate.Designer.cs
generated
Normal file
@@ -0,0 +1,173 @@
|
||||
// <auto-generated />
|
||||
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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.12");
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.BusinessConfigRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SupportEmail")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BusinessConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.ContentCardRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BelongsToPage")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Group")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Header")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ContentCards");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.HomePageRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BookHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CallHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderLine1")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderLine2")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SecondaryHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("HomePage");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.RepairRequestMediaRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("MediaPath")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RepairRequestMedia");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.RepairRequestRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Brand")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RepairRequests");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
125
Migrations/20260424050555_InitialCreate.cs
Normal file
125
Migrations/20260424050555_InitialCreate.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ApplianceRepair.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "BusinessConfig",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
|
||||
SupportEmail = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_BusinessConfig", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ContentCards",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
BelongsToPage = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Group = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Header = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Text = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ContentCards", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "HomePage",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
HeaderLine1 = table.Column<string>(type: "TEXT", nullable: true),
|
||||
HeaderLine2 = table.Column<string>(type: "TEXT", nullable: true),
|
||||
HeaderText = table.Column<string>(type: "TEXT", nullable: true),
|
||||
CallHeaderText = table.Column<string>(type: "TEXT", nullable: true),
|
||||
BookHeaderText = table.Column<string>(type: "TEXT", nullable: true),
|
||||
SecondaryHeaderText = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_HomePage", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RepairRequestMedia",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
RequestNumber = table.Column<string>(type: "TEXT", nullable: true),
|
||||
MediaPath = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RepairRequestMedia", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RepairRequests",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
RequestNumber = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Type = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Brand = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Notes = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Phone = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RepairRequests", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
170
Migrations/DatabaseContextModelSnapshot.cs
Normal file
170
Migrations/DatabaseContextModelSnapshot.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using ApplianceRepair;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ApplianceRepair.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
partial class DatabaseContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.12");
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.BusinessConfigRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SupportEmail")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BusinessConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.ContentCardRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BelongsToPage")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Group")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Header")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ContentCards");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.HomePageRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BookHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CallHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderLine1")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderLine2")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SecondaryHeaderText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("HomePage");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.RepairRequestMediaRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("MediaPath")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RepairRequestMedia");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ApplianceRepair.RepairRequestRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Brand")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RepairRequests");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Models.cs
108
Models.cs
@@ -22,17 +22,58 @@
|
||||
public class HomePageModel : HomePageRecord
|
||||
{
|
||||
public static string PageName = "Home";
|
||||
|
||||
public enum ContentCardTypes
|
||||
{
|
||||
Service,
|
||||
Services,
|
||||
Trust,
|
||||
}
|
||||
|
||||
public string BusinessName { get; set; }
|
||||
public string FormattedPhoneNumber { get; set; }
|
||||
public string PhoneNumberCallLink { get; set; }
|
||||
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
public string FormattedPhoneNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PhoneNumber))
|
||||
{
|
||||
return $"({PhoneNumber[0..3]})-{PhoneNumber[3..6]}-{PhoneNumber[6..10]}";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string PhoneNumberCallLink
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PhoneNumber))
|
||||
{
|
||||
return $"tel:{PhoneNumber}";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string CopyrightText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BusinessName))
|
||||
{
|
||||
return $"© {DateTime.Now.Year} {BusinessName}. All rights reserved.";
|
||||
}
|
||||
|
||||
return $"© {DateTime.Now.Year} All rights reserved.";
|
||||
}
|
||||
}
|
||||
|
||||
public List<ContentCardModel> ServicesCards { get; set; }
|
||||
|
||||
public List<ContentCardModel> TrustCards { get; set; }
|
||||
|
||||
public HomePageModel()
|
||||
@@ -40,44 +81,57 @@
|
||||
HeaderLine1 = string.Empty;
|
||||
HeaderLine2 = string.Empty;
|
||||
HeaderText = string.Empty;
|
||||
HeaderButton1Text = string.Empty;
|
||||
HeaderButton1Link = string.Empty;
|
||||
HeaderButton2Text = string.Empty;
|
||||
HeaderButton2Link = string.Empty;
|
||||
CallHeaderText = string.Empty;
|
||||
BookHeaderText = string.Empty;
|
||||
SecondaryHeaderText = string.Empty;
|
||||
CopyrightText = string.Empty;
|
||||
|
||||
BusinessName = "Appliance Pro";
|
||||
FormattedPhoneNumber = "(555) 555-5555";
|
||||
PhoneNumberCallLink = $"tel:{FormattedPhoneNumber}";
|
||||
BusinessName = string.Empty;
|
||||
PhoneNumber = string.Empty;
|
||||
|
||||
ServicesCards = [];
|
||||
TrustCards = [];
|
||||
}
|
||||
|
||||
public HomePageModel(HomePageRecord record)
|
||||
public HomePageModel(
|
||||
HomePageRecord homePageRecord,
|
||||
BusinessConfigRecord businessConfigRecord,
|
||||
List<ContentCardRecord> serviceCards,
|
||||
List<ContentCardRecord> trustCards)
|
||||
{
|
||||
HeaderLine1 = record.HeaderLine1;
|
||||
HeaderLine2 = record.HeaderLine2;
|
||||
HeaderText = record.HeaderText;
|
||||
HeaderButton1Text = record.HeaderButton1Text;
|
||||
HeaderButton1Link = record.HeaderButton1Link;
|
||||
HeaderButton2Text = record.HeaderButton2Text;
|
||||
HeaderButton2Link = record.HeaderButton2Link;
|
||||
SecondaryHeaderText = record.SecondaryHeaderText;
|
||||
CopyrightText = record.CopyrightText;
|
||||
HeaderLine1 = homePageRecord.HeaderLine1;
|
||||
HeaderLine2 = homePageRecord.HeaderLine2;
|
||||
HeaderText = homePageRecord.HeaderText;
|
||||
CallHeaderText = homePageRecord.CallHeaderText;
|
||||
BookHeaderText = homePageRecord.BookHeaderText;
|
||||
SecondaryHeaderText = homePageRecord.SecondaryHeaderText;;
|
||||
|
||||
BusinessName = "Appliance Pro";
|
||||
FormattedPhoneNumber = "(555) 555-5555";
|
||||
PhoneNumberCallLink = $"tel:{FormattedPhoneNumber}";
|
||||
BusinessName = businessConfigRecord.Name ?? "";
|
||||
PhoneNumber = businessConfigRecord.PhoneNumber ?? "";
|
||||
|
||||
ServicesCards = [];
|
||||
TrustCards = [];
|
||||
}
|
||||
}
|
||||
|
||||
public class RepairRequestModel : RepairRequestRecord
|
||||
foreach (var card in serviceCards)
|
||||
{
|
||||
ServicesCards.Add(new ContentCardModel(card));
|
||||
}
|
||||
|
||||
foreach (var card in trustCards)
|
||||
{
|
||||
TrustCards.Add(new ContentCardModel(card));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RepairRequestModel : RepairRequestRecord { }
|
||||
|
||||
public class BusinessInfoModel : BusinessConfigRecord
|
||||
{
|
||||
public BusinessInfoModel(BusinessConfigRecord record)
|
||||
{
|
||||
Name = record.Name;
|
||||
PhoneNumber = record.PhoneNumber;
|
||||
SupportEmail = record.SupportEmail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
Program.cs
10
Program.cs
@@ -17,6 +17,8 @@ builder.Services.AddLogging();
|
||||
builder.Services.AddScoped<BusinessConfigReader>();
|
||||
builder.Services.AddScoped<ContentCardReader>();
|
||||
builder.Services.AddScoped<HomePageReader>();
|
||||
builder.Services.AddScoped<RepairRequestReader>();
|
||||
builder.Services.AddScoped<RepairRequestMediaReader>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@@ -25,12 +27,16 @@ using (var scope = app.Services.CreateScope())
|
||||
var services = scope.ServiceProvider;
|
||||
try
|
||||
{
|
||||
services.GetRequiredService<DatabaseContext>().Database.EnsureCreated();
|
||||
var context = services.GetRequiredService<DatabaseContext>();
|
||||
|
||||
await context.Database.MigrateAsync();
|
||||
|
||||
await DatabaseContext.Initialize(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogError(ex, "An error occurred creating the DB.");
|
||||
logger.LogError(ex, "An error occurred while migrating or seeding the database.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
Services.cs
110
Services.cs
@@ -10,37 +10,27 @@ namespace ApplianceRepair
|
||||
return records;
|
||||
}
|
||||
|
||||
public async Task<HomePageModel?> ReadLatestRecordWithModel(ContentCardReader contentCardReader)
|
||||
{
|
||||
var record = await db.HomePage.OrderByDescending(page => page.Id).FirstOrDefaultAsync();
|
||||
if (record == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var model = new HomePageModel(record);
|
||||
var pageName = HomePageModel.PageName;
|
||||
|
||||
var services = await contentCardReader.ReadAllByPageAndGroup(pageName, HomePageModel.ContentCardTypes.Service.ToString()) ?? [];
|
||||
foreach (var card in services)
|
||||
{
|
||||
model.ServicesCards.Add(new ContentCardModel(card));
|
||||
}
|
||||
|
||||
var trust = await contentCardReader.ReadAllByPageAndGroup(pageName, HomePageModel.ContentCardTypes.Trust.ToString()) ?? [];
|
||||
foreach (var card in trust)
|
||||
{
|
||||
model.TrustCards.Add(new ContentCardModel(card));
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task AddRecord(HomePageRecord record)
|
||||
{
|
||||
record.CreatedAt = DateTime.Now;
|
||||
record.UpdatedAt = DateTime.Now;
|
||||
await db.AddAsync(record);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateRecord(HomePageRecord record)
|
||||
{
|
||||
var found = db.HomePage.Where((page) => page.Id == record.Id).FirstOrDefault();
|
||||
if (found == null)
|
||||
{
|
||||
await AddRecord(record);
|
||||
}
|
||||
else
|
||||
{
|
||||
db.HomePage.Update(record);
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class ContentCardReader(DatabaseContext db)
|
||||
@@ -58,6 +48,7 @@ namespace ApplianceRepair
|
||||
public async Task AddRecord(ContentCardRecord record)
|
||||
{
|
||||
await db.ContentCards.AddAsync(record);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateRecord(ContentCardRecord record)
|
||||
@@ -81,5 +72,72 @@ namespace ApplianceRepair
|
||||
{
|
||||
return await db.BusinessConfig.OrderByDescending(page => page.Id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task AddRecord(BusinessConfigRecord record)
|
||||
{
|
||||
await db.BusinessConfig.AddAsync(record);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateRecord(BusinessConfigRecord record)
|
||||
{
|
||||
var found = db.BusinessConfig.Where((config) => config.Id == record.Id).FirstOrDefault();
|
||||
if (found == null)
|
||||
{
|
||||
await AddRecord(record);
|
||||
}
|
||||
else
|
||||
{
|
||||
db.BusinessConfig.Update(record);
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class RepairRequestReader(DatabaseContext db)
|
||||
{
|
||||
public async Task<RepairRequestRecord?> ReadByRequestNumber(string requestNumber)
|
||||
{
|
||||
return await db.RepairRequests.Where((record) => record.RequestNumber == requestNumber).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<RepairRequestRecord>> ReadAll()
|
||||
{
|
||||
return await db.RepairRequests.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task AddRecord(RepairRequestRecord record)
|
||||
{
|
||||
await db.RepairRequests.AddAsync(record);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateRecord(RepairRequestRecord record)
|
||||
{
|
||||
var found = db.RepairRequests.Where((config) => config.Id == record.Id).FirstOrDefault();
|
||||
if (found == null)
|
||||
{
|
||||
await AddRecord(record);
|
||||
}
|
||||
else
|
||||
{
|
||||
db.RepairRequests.Update(record);
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class RepairRequestMediaReader(DatabaseContext db)
|
||||
{
|
||||
public async Task<List<RepairRequestMediaRecord>> ReadAllByRequestNumber(string requestNumber)
|
||||
{
|
||||
return await db.RepairRequestMedia.Where((record) => record.RequestNumber == requestNumber).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task AddRecord(RepairRequestMediaRecord record)
|
||||
{
|
||||
await db.RepairRequestMedia.AddAsync(record);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
wwwroot/uploads/exvwoomm.qgm.jpg
Normal file
0
wwwroot/uploads/exvwoomm.qgm.jpg
Normal file
BIN
wwwroot/uploads/uefue0ou.esy.png
Normal file
BIN
wwwroot/uploads/uefue0ou.esy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
Reference in New Issue
Block a user