WBC 2026 revisions

This commit is contained in:
2026-09-02 13:48:27 -04:00
parent 8b1fe308ab
commit fd3b8e1c62
22 changed files with 339 additions and 130 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "webform",
"runtimeExecutable": "dotnet",
"runtimeArgs": ["run", "--urls", "http://localhost:5052"],
"port": 5052
}
]
}
+7
View File
@@ -75,6 +75,13 @@
return "";
}
}
window.resetWizardScroll = function () {
var content = document.querySelector('.k-wizard-content');
if (content) {
content.scrollTop = 0;
}
window.scrollTo(0, 0);
}
</script>
<pre>@errMsg</pre>
@* @if (appState != null)
+104 -41
View File
@@ -26,9 +26,9 @@ else if (ShowWizard)
<div class="container">
<div class="row">
<div class="col-12">
<TelerikWizard @bind-Value="@Value" OnFinish="OnFinishHandler" Width="100%" Height="95vh" Class="sbWizard" StepperPosition=WizardStepperPosition.Top>
<TelerikWizard Value="@Value" ValueChanged="@OnWizardValueChanged" OnFinish="OnFinishHandler" Width="100%" Height="95vh" Class="sbWizard" StepperPosition=WizardStepperPosition.Top>
<WizardSteps>
<WizardStep Label="Introduction" Icon="@SvgIcon.Globe" Valid="@IsAudienceChoiceValid">
<WizardStep Label="Introduction" Icon="@SvgIcon.Bell" Valid="@IsAudienceChoiceValid">
<Content>
<TelerikForm Model="@cardType" @ref="@IntroForm">
<FormItems>
@@ -47,7 +47,7 @@ else if (ShowWizard)
<p>Let us handle the rest!</p>
</div>
<div>
<img src="/img/HomeCollage.png" class="img-fluid" />
<img src="/img/HomeCollage.png" class="img-fluid card-preview-img" />
</div>
<br />
<div class="px-sm-5 mb-2">
@@ -68,7 +68,7 @@ else if (ShowWizard)
@* *@
@* Step 1 - greeting card vs postcard *@
@* *@
<WizardStep Label="Card Type" OnChange="@OnCardChoiceStepChange">
<WizardStep Label="Card Type" Icon="@SvgIcon.LayoutSideBySide" OnChange="@OnCardChoiceStepChange">
<Content>
<TelerikForm Model="@cardType" @ref="@cardTypeForm">
<FormItems>
@@ -77,7 +77,7 @@ else if (ShowWizard)
<div class="container">
<div class="row">
<div class="col-12">
<h1 class="text-center">Step 1 - Choose a Card Type</h1>
<h1 class="text-center">Choose a Card Type</h1>
</div>
<div class="col-12 text-center mb-3">
<TelerikButtonGroup SelectionMode="@ButtonGroupSelectionMode.Single">
@@ -94,11 +94,11 @@ else if (ShowWizard)
<li>Unique and bold presentation!</li>
<li>Large trifold piece</li>
<li>Coupons are detachable and easy to remove, offering great convenience for your customers!</li>
<li>Leave it to us - we select, print, sort, stuff and mail for just <strong class="text-primary text-nowrap">$1.14 each</strong></li>
<li>Leave it to us - we select, print, sort, stuff and mail for just <strong class="text-primary text-nowrap">$1.19 each</strong></li>
</ul>
</div>
<div class="col-sm-8 text-center mb-3">
<img style="width:50%;height:50%" class="img-fluid" src="/img/GreetingCards.png" />
<img style="max-height:55vh; max-width:120%; width:auto; height:auto" class="img-fluid card-preview-img" src="/img/GreetingCards.png" alt="Sample greeting cards" />
</div>
}
else
@@ -109,11 +109,11 @@ else if (ShowWizard)
<li>Premium paper, Jumbo-Sized (8&frac12; x 6 inches)</li>
<li>UV gloss-coated</li>
<li>Choose from one of our pre-selected options, or ask for a custom design!</li>
<li>Full service - select, print, sort, mail for just <strong class="text-primary text-nowrap">92&#162; each</strong></li>
<li>Full service - select, print, sort, mail for just <strong class="text-primary text-nowrap">97&#162; each</strong></li>
</ul>
</div>
<div class="col-sm-8 text-center mb-3">
<img style="width:60%;height:60%" class="img-fluid" src="/img/Postcards.png" />
<img style="max-height:55vh; max-width:120%; width:auto; height:auto" class="img-fluid card-preview-img" src="/img/Postcards.png" alt="Sample postcards" />
</div>
}
</div>
@@ -130,7 +130,7 @@ else if (ShowWizard)
@* *@
@* Step 2 - selecting card design *@
@* *@
<WizardStep Label="Card Design" OnChange="@OnDesignStepChange">
<WizardStep Label="Card Design" Icon="@SvgIcon.Palette" OnChange="@OnDesignStepChange">
<Content>
<TelerikForm Model="@custOptions" @ref="@customizationForm">
<FormValidation>
@@ -171,44 +171,44 @@ else if (ShowWizard)
{
@if (isPostcard)
{
<img style="width:40%;height:40%" src="/img/Postcard1.jpg" class="img-fluid" alt="Automotive" />
<img style="max-width:40%" src="/img/Postcard1.jpg" class="img-fluid card-preview-img" alt="Automotive" />
}
else
{
<img style="width:40%;height:40%" src="/img/Greeting1_sd.png" class="img-fluid" alt="Autmotive" />
<img style="max-width:40%" src="/img/Greeting1_sd.png" class="img-fluid card-preview-img" alt="Automotive" />
}
}
else if (designTwo)
{
@if (isPostcard)
{
<img style="width:40%;height:40%" src="/img/Postcard2.jpg" class="img-fluid" alt="Winter" />
<img style="max-width:40%" src="/img/Postcard2.jpg" class="img-fluid card-preview-img" alt="Winter" />
}
else
{
<img style="width:40%;height:40%" src="/img/Greeting2_sd.png" class="img-fluid" alt="Winter" />
<img style="max-width:40%" src="/img/Greeting2_sd.png" class="img-fluid card-preview-img" alt="Winter" />
}
}
else if (designThree)
{
@if (isPostcard)
{
<img style="width:40%;height:40%" src="/img/Postcard3.jpg" class="img-fluid" alt="Puppy" />
<img style="max-width:40%" src="/img/Postcard3.jpg" class="img-fluid card-preview-img" alt="Puppy" />
}
else
{
<img style="width:40%;height:40%" src="/img/Greeting3_sd.png" class="img-fluid" alt="Puppy" />
<img style="max-width:40%" src="/img/Greeting3_sd.png" class="img-fluid card-preview-img" alt="Puppy" />
}
}
else if (designFour)
{
@if (isPostcard)
{
<img style="width:40%;height:40%" src="/img/Postcard4.jpg" class="img-fluid" alt="Beach" />
<img style="max-width:40%" src="/img/Postcard4.jpg" class="img-fluid card-preview-img" alt="Beach" />
}
else
{
<img style="width:40%;height:40%" src="/img/Greeting4_sd.png" class="img-fluid" alt="Beach" />
<img style="max-width:40%" src="/img/Greeting4_sd.png" class="img-fluid card-preview-img" alt="Beach" />
}
}
else if (designCustom)
@@ -229,7 +229,7 @@ else if (ShowWizard)
@* *@
@* Step 3 - Greeting, verse, signature *@
@* *@
<WizardStep Label="Customization" OnChange="@OnMessagingStepChange">
<WizardStep Label="Customization" Icon="@SvgIcon.Signature" OnChange="@OnMessagingStepChange">
<Content>
<TelerikForm Model="@messagingOptions" @ref="@messagingForm">
<FormItems>
@@ -247,19 +247,19 @@ else if (ShowWizard)
@if (greetingOne)
{
<div class="p-5">
<img style="width:25%;height:25%" src="/img/greetings/HappyHolidays.png" class="img-fluid" />
<img style="max-width:25%" src="/img/greetings/HappyHolidays.png" class="img-fluid card-preview-img" alt="Happy Holidays greeting preview" />
</div>
}
else if (greetingTwo)
{
<div class="p-5">
<img style="width:20%;height:20%" src="/img/greetings/MerryChristmas.png" class="img-fluid" />
<img style="max-width:20%" src="/img/greetings/MerryChristmas.png" class="img-fluid card-preview-img" alt="Merry Christmas greeting preview" />
</div>
}
else if (greetingThree)
{
<div class="p-5">
<img style="width:20%;height:20%" src="/img/greetings/SeasonsGreetings.png" class="img-fluid" />
<img style="max-width:20%" src="/img/greetings/SeasonsGreetings.png" class="img-fluid card-preview-img" alt="Season's Greetings preview" />
</div>
}
</div>
@@ -273,19 +273,20 @@ else if (ShowWizard)
</TelerikButtonGroup>
@if (verseOne)
{
<p class="fst-italic">We are grateful that you've chosen to do business with us.</p>
<p class="fst-italic">Thank You!</p>
<p class="fst-italic">Wishing you all the best this holiday season and in the New Year.</p>
<p class="fst-italic">Your support means so much to us.</p>
<p class="fst-italic">Thank you for choosing our team to keep you on the road.</p>
<p class="fst-italic">Wishing you a wonderful holiday season and a happy New Year!</p>
}
else if (verseTwo)
{
<p class="fst-italic">Thank you for putting your trust in us.</p>
<p>We wish you a happy and safe holiday season.</p>
<p class="fst-italic">May 2026 bring joy and peace!</p>
<p class="fst-italic">Warmest wishes this holiday season from all of us!</p>
<p class="fst-italic">Thank you for your continued trust and support.</p>
<p class="fst-italic">May 2027 bring you happiness, good health, and many safe miles ahead.</p>
}
else if (verseThree)
{
<p class="fst-italic">Thank you for trusting your vehicle to us. We appreciate your business.</p>
<p class="fst-italic">Its been our pleasure serving you throughout the year.</p>
<p class="fst-italic">Were grateful for your business and look forward to seeing you in 2027.</p>
<p class="fst-italic">Merry Christmas and Happy New Year!</p>
}
</div>
@@ -333,7 +334,7 @@ else if (ShowWizard)
@* *@
@* Step 4 - Logo Selection *@
@* *@
<WizardStep Label="Logos" OnChange="@OnLogoStepChange">
<WizardStep Label="Logos" Icon="@SvgIcon.Image" OnChange="@OnLogoStepChange">
<Content>
<TelerikForm Model="@logoOptions" @ref="@logoForm">
<FormItems>
@@ -368,23 +369,71 @@ else if (ShowWizard)
@* *@
@* Step 5 - Location information *@
@* *@
<WizardStep Label="Location Info" OnChange="@OnLocationStepChange" Valid="@isLocationInfoValid">
<WizardStep Label="Location Info" Icon="@SvgIcon.MapMarker" OnChange="@OnLocationStepChange" Valid="@isLocationInfoValid">
<Content>
<TelerikForm Model="@locationInfo" @ref="@locationForm">
<FormItems>
<FormItem>
<Template>
<div class="container">
<div class="row">
<div class="col-12">
<TelerikForm Model="@locationInfo" @ref="@locationForm" Columns="2" ColumnSpacing="25px">
<div class="col-12 mb-3">
<h1 class="text-center">Tell Us About You!</h1>
<p class="text-center text-muted">Fields marked with <span class="text-danger">*</span> are required.</p>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="LocationName">Location Name <span class="text-danger">*</span></label>
<TelerikTextBox Id="LocationName" @bind-Value="@locationInfo.LocationName" Width="100%" MaxLength="100"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="Manager">Store Manager <span class="text-danger">*</span></label>
<TelerikTextBox Id="Manager" @bind-Value="@locationInfo.Manager" Width="100%" MaxLength="100"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="Address">Address <span class="text-danger">*</span></label>
<TelerikTextBox Id="Address" @bind-Value="@locationInfo.Address" Width="100%" MaxLength="150"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="City">City <span class="text-danger">*</span></label>
<TelerikTextBox Id="City" @bind-Value="@locationInfo.City" Width="100%" MaxLength="100"></TelerikTextBox>
</div>
<div class="col-md-3 mb-3">
<label style="display:block" for="State">State <span class="text-danger">*</span></label>
<TelerikDropDownList Id="State" Data="@UsStates" @bind-Value="@locationInfo.State" Width="100%"></TelerikDropDownList>
</div>
<div class="col-md-3 mb-3">
<label style="display:block" for="Zip">Zip <span class="text-danger">*</span></label>
<TelerikTextBox Id="Zip" @bind-Value="@locationInfo.Zip" Width="100%" MaxLength="10" Placeholder="12345"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="PhoneNumber">Store Phone Number <span class="text-danger">*</span></label>
<TelerikTextBox Id="PhoneNumber" @bind-Value="@locationInfo.PhoneNumber" Width="100%" MaxLength="20" Placeholder="(555) 555-5555"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="ContactName">Contact Name <span class="text-danger">*</span></label>
<TelerikTextBox Id="ContactName" @bind-Value="@locationInfo.ContactName" Width="100%" MaxLength="100"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="ContactPhone">Contact Phone <span class="text-danger">*</span></label>
<TelerikTextBox Id="ContactPhone" @bind-Value="@locationInfo.ContactPhone" Width="100%" MaxLength="20" Placeholder="(555) 555-5555"></TelerikTextBox>
</div>
<div class="col-md-6 mb-3">
<label style="display:block" for="ContactEmail">Your Email Address <span class="text-danger">*</span></label>
<TelerikTextBox Id="ContactEmail" @bind-Value="@locationInfo.ContactEmail" Width="100%" MaxLength="150" Placeholder="name@example.com"></TelerikTextBox>
</div>
</div>
</div>
</Template>
</FormItem>
</FormItems>
<FormButtons />
</TelerikForm>
</div>
</div>
</div>
</Content>
</WizardStep>
@* *@
@* Step 6 - Payment *@
@* *@
<WizardStep Label="Payment Info">
<WizardStep Label="Payment Info" Icon="@SvgIcon.WalletOutline">
<Content>
<TelerikForm Model="@paymentInfo" @ref="@paymentForm">
<FormItems>
@@ -392,7 +441,21 @@ else if (ShowWizard)
<Template>
<div class="container">
<div class="row">
<div class="col-12 mb-4">
<div class="order-summary mx-auto text-start">
<h4 class="text-center mb-3">Review Your Selections</h4>
<dl class="row mb-0">
<dt class="col-5 col-sm-4">Card Type</dt><dd class="col-7 col-sm-8">@SummaryCardType</dd>
<dt class="col-5 col-sm-4">Design</dt><dd class="col-7 col-sm-8">@SummaryDesign</dd>
<dt class="col-5 col-sm-4">Greeting</dt><dd class="col-7 col-sm-8">@SummaryGreeting</dd>
<dt class="col-5 col-sm-4">Verse</dt><dd class="col-7 col-sm-8">@SummaryVerse</dd>
<dt class="col-5 col-sm-4">Signature</dt><dd class="col-7 col-sm-8">@SummarySignature</dd>
<dt class="col-5 col-sm-4">Logo</dt><dd class="col-7 col-sm-8">@SummaryLogos</dd>
</dl>
</div>
</div>
<div class="col-12">
<h1 class="text-center">How Would You Like to Pay?</h1>
<TelerikButtonGroup SelectionMode="@ButtonGroupSelectionMode.Single" Class="vertical-buttons block-buttons mb-5">
<ButtonGroupToggleButton @bind-Selected="@ccOnFile">Credit Card On File</ButtonGroupToggleButton>
<ButtonGroupToggleButton @bind-Selected="@callWithInfo">Call With Payment Info</ButtonGroupToggleButton>
@@ -412,15 +475,15 @@ else if (ShowWizard)
else if (check)
{
<h4>I'll be sending in a check</h4>
<p>I'll be sending in a check by the invoice's due date (10/24/2025).</p>
<p>I'll be sending in a check by the invoice's due date (10/31/2026).</p>
}
</div>
<hr />
<div class="col-12">
<label style="display:block" for="RequestedQuantity" class="text-center mb-3">Requested Quantity</label>
<TelerikTextBox class="mb-3" Id="RequestedQuantity" @bind-Value="@requestedQuantity" MaxLength="6" Width="15rem"></TelerikTextBox>
<label style="display:block" for="RequestedQuantity" class="text-center mb-3">Requested Quantity <span class="text-danger">*</span></label>
<TelerikTextBox class="mb-3" Id="RequestedQuantity" @bind-Value="@requestedQuantity" MaxLength="6" Width="15rem" Placeholder="e.g. 250"></TelerikTextBox>
<label style="display:block" for="AdditionalComments" class="text-center mb-3">Additional Notes</label>
<TelerikTextArea class="mb-3" Id="CustomSignature" @bind-Value="@additionalComments" Rows="8" Cols="100" MaxLength="2500"></TelerikTextArea>
<TelerikTextArea class="mb-3" Id="AdditionalComments" @bind-Value="@additionalComments" Rows="8" Cols="100" MaxLength="2500"></TelerikTextArea>
</div>
</div>
</div>
+108 -80
View File
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using Telerik.Blazor;
using Telerik.Blazor.Components;
using Telerik.SvgIcons;
@@ -17,9 +19,24 @@ public partial class Home
[CascadingParameter]
public CascadingAppState appState { get; set; } = default!;
[Inject]
public IJSRuntime JS { get; set; } = default!;
public async Task OnWizardValueChanged(int newValue)
{
Value = newValue;
await JS.InvokeVoidAsync("resetWizardScroll");
}
async Task OnFinishHandler()
//private void SaveIt()
{
if (!int.TryParse(requestedQuantity, out int parsedQuantity) || parsedQuantity <= 0)
{
await Dialogs.AlertAsync("Please enter a valid Requested Quantity before submitting.", "You cannot proceed");
return;
}
using (var em = new kmCommonLibsCore.Emails() { HandleOptOuts = false, SendMethod = enuSendMethod.OnsiteServer })
{
// Parsing the submitted form to pull the relevant information
@@ -147,7 +164,7 @@ public partial class Home
[CascadingParameter]
public DialogFactory Dialogs { get; set; } = default!;
public bool ProgramClosed { get; set; } = true;
public bool ProgramClosed { get; set; } = false;
public bool ShowWizard { get; set; } = true;
public int Value { get; set; } = 0;
@@ -162,12 +179,6 @@ public partial class Home
public CardType cardType { get; set; } = new CardType();
public bool isGreetingCard { get; set; } = true;
public bool isPostcard { get; set; } = false;
public string audienceType { get; set; } = string.Empty;
public List<AudienceType> audiences { get; set; } = new List<AudienceType>
{
new AudienceType() {AudienceDescription="Send to my BEST CUSTOMERS"},
new AudienceType() {AudienceDescription="Send to Great Prospects as well as Customers who haven't been in during the past 8 months"}
};
// Variables for selecting specific design
public TelerikForm customizationForm { get; set; } = new();
@@ -203,28 +214,18 @@ public partial class Home
public bool logoOnEnvelope = true;
public bool isLogoValid = true;
// Variables for offer selection (plastic cards only)
public TelerikForm offerForm { get; set; } = new();
public OfferOptions offerOptions { get; set; } = new OfferOptions();
public bool[] bigOffers = new bool[6];
public bool[] smallOffers = new bool[12];
public bool isOfferSelectionValid = false;
// Location information
public TelerikForm locationForm { get; set; } = new();
public LocationInfo locationInfo { get; set; } = new LocationInfo();
public string locationName { get; set; } = string.Empty;
public string manager { get; set; } = string.Empty;
public string address { get; set; } = string.Empty;
public string city { get; set; } = string.Empty;
public string state { get; set; } = string.Empty;
public string zip { get; set; } = string.Empty;
public string phoneNumber { get; set; } = string.Empty;
public string contactName { get; set; } = string.Empty;
public string contactPhone { get; set; } = string.Empty;
public string contactEmail { get; set; } = string.Empty;
public bool isLocationInfoValid { get; set; } = false;
public static readonly List<string> UsStates = new()
{
"AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA",
"ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR",
"PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"
};
// Payment information
public TelerikForm paymentForm { get; set; } = new();
public PaymentInfo paymentInfo { get; set; } = new PaymentInfo();
@@ -263,61 +264,98 @@ public partial class Home
isLogoValid = true;
}
public async void OnOfferStepChange(WizardStepChangeEventArgs args)
{
if (isPostcard)
{
isOfferSelectionValid = true;
}
else
{
int bigOfferCount = 0;
foreach (bool selection in bigOffers)
{
if (selection)
bigOfferCount++;
}
int smallOfferCount = 0;
foreach (bool selection in smallOffers)
{
if (selection)
smallOfferCount++;
}
if (smallOfferCount == 4 && bigOfferCount == 2)
isOfferSelectionValid = true;
else
isOfferSelectionValid = false;
if (!isOfferSelectionValid)
{
args.IsCancelled = true;
await Dialogs.AlertAsync("Please select the proper amount of offers.", "You cannot proceed");
}
}
}
public async void OnLocationStepChange(WizardStepChangeEventArgs args)
{
isLocationInfoValid = !string.IsNullOrWhiteSpace(locationInfo.ContactEmail) &&
!string.IsNullOrWhiteSpace(locationInfo.ContactPhone) &&
!string.IsNullOrWhiteSpace(locationInfo.ContactName) &&
!string.IsNullOrWhiteSpace(locationInfo.City) &&
!string.IsNullOrWhiteSpace(locationInfo.State) &&
!string.IsNullOrWhiteSpace(locationInfo.Zip) &&
!string.IsNullOrWhiteSpace(locationInfo.PhoneNumber) &&
!string.IsNullOrWhiteSpace(locationInfo.LocationName) &&
!string.IsNullOrWhiteSpace(locationInfo.Address) &&
!string.IsNullOrWhiteSpace(locationInfo.Manager);
var missingFields = new List<string>();
if (string.IsNullOrWhiteSpace(locationInfo.LocationName)) missingFields.Add("Location Name");
if (string.IsNullOrWhiteSpace(locationInfo.Manager)) missingFields.Add("Store Manager");
if (string.IsNullOrWhiteSpace(locationInfo.Address)) missingFields.Add("Address");
if (string.IsNullOrWhiteSpace(locationInfo.City)) missingFields.Add("City");
if (string.IsNullOrWhiteSpace(locationInfo.State)) missingFields.Add("State");
if (string.IsNullOrWhiteSpace(locationInfo.Zip)) missingFields.Add("Zip");
if (string.IsNullOrWhiteSpace(locationInfo.PhoneNumber)) missingFields.Add("Phone Number");
if (string.IsNullOrWhiteSpace(locationInfo.ContactName)) missingFields.Add("Contact Name");
if (string.IsNullOrWhiteSpace(locationInfo.ContactPhone)) missingFields.Add("Contact Phone");
if (string.IsNullOrWhiteSpace(locationInfo.ContactEmail)) missingFields.Add("Your Email Address");
var formatErrors = new List<string>();
if (!string.IsNullOrWhiteSpace(locationInfo.Zip) && !Regex.IsMatch(locationInfo.Zip, @"^\d{5}(-\d{4})?$"))
formatErrors.Add("Zip must be a valid 5-digit ZIP code.");
if (!string.IsNullOrWhiteSpace(locationInfo.ContactEmail) && !Regex.IsMatch(locationInfo.ContactEmail, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"))
formatErrors.Add("Your Email Address doesn't look like a valid email.");
if (!string.IsNullOrWhiteSpace(locationInfo.PhoneNumber) && Regex.Replace(locationInfo.PhoneNumber, @"\D", "").Length < 10)
formatErrors.Add("Phone Number should include an area code (10 digits).");
if (!string.IsNullOrWhiteSpace(locationInfo.ContactPhone) && Regex.Replace(locationInfo.ContactPhone, @"\D", "").Length < 10)
formatErrors.Add("Contact Phone should include an area code (10 digits).");
isLocationInfoValid = missingFields.Count == 0 && formatErrors.Count == 0;
if (!isLocationInfoValid)
{
args.IsCancelled = true;
await Dialogs.AlertAsync("Please fill out all required fields.", "You cannot proceed");
var messageParts = new List<string>();
if (missingFields.Count > 0)
messageParts.Add("Please fill out: " + string.Join(", ", missingFields) + ".");
messageParts.AddRange(formatErrors);
await Dialogs.AlertAsync(string.Join("\n", messageParts), "You cannot proceed");
}
}
#region "Order Review Summary (Payment step)"
public string SummaryCardType => isPostcard ? "Postcard" : "Greeting Card";
public string SummaryDesign
{
get
{
if (designCustom) return "Custom design (our team will follow up with you)";
var number = designOne ? "1" : designTwo ? "2" : designThree ? "3" : designFour ? "4" : "-";
return $"{SummaryCardType} - Design {number}";
}
}
public string SummaryGreeting =>
greetingOne ? "Happy Holidays" :
greetingTwo ? "Merry Christmas" :
greetingThree ? "Season's Greetings" : "-";
public string SummaryVerse =>
verseOne ? "\"Your support means so much to us. Thank you for choosing our team to keep you on the road. Wishing you a wonderful holiday season and a happy New Year!\"" :
verseTwo ? "\"Warmest wishes this holiday season from all of us! Thank you for your continued trust and support. May 2027 bring you happiness, good health, and many safe miles ahead.\"" :
verseThree ? "\"Its been our pleasure serving you throughout the year. Were grateful for your business and look forward to seeing you in 2027. Merry Christmas and Happy New Year!\"" : "";
public string SummarySignature
{
get
{
if (sigOne) return "From Your Friends";
if (sigTwo)
{
var parts = new List<string>();
if (!string.IsNullOrWhiteSpace(customName)) parts.Add(customName);
if (!string.IsNullOrWhiteSpace(customTitle)) parts.Add(customTitle);
if (!string.IsNullOrWhiteSpace(customPhone)) parts.Add(customPhone);
return parts.Count > 0 ? string.Join(", ", parts) : "Name, Title, Phone Number (not yet entered)";
}
if (sigThree) return string.IsNullOrWhiteSpace(customSignature) ? "Custom message (not yet entered)" : customSignature;
return "-";
}
}
public string SummaryLogos
{
get
{
var items = new List<string>();
if (logoOnCard) items.Add("On Card");
if (isGreetingCard && logoOnEnvelope) items.Add("On Envelope");
return items.Count == 0 ? "None" : string.Join(", ", items);
}
}
#endregion
#region "Models and Such"
public class CardType
@@ -343,11 +381,6 @@ public partial class Home
public string option { get; set; } = string.Empty;
}
public class OfferOptions
{
public string option { get; set; } = string.Empty;
}
public class LocationInfo
{
[Required, Display(Name = "Location Name")]
@@ -376,10 +409,5 @@ public partial class Home
{
public string info { get; set; } = string.Empty;
}
public class AudienceType
{
public string AudienceDescription { get; set; } = string.Empty;
}
#endregion
}
+104 -4
View File
@@ -1,19 +1,53 @@
/* Holiday palette: cranberry primary, pine secondary, warm gold/cream accents.
Kendo/Telerik components read their theme from these --kendo-* custom
properties, so overriding them here retints the wizard's buttons, selected
toggle states, dropdowns, and stepper without touching every component. */
:root {
--holiday-red: #b3202d;
--holiday-red-hover: #971a26;
--holiday-red-active: #7d1620;
--holiday-green: #1f5c3f;
--holiday-gold: #c9a227;
--holiday-cream: #fbf7ef;
/* !important: the Telerik theme stylesheet loads after app.css and
re-declares these same variables on :root, which would otherwise win
the cascade at equal specificity and silently discard our palette. */
--kendo-color-primary: var(--holiday-red) !important;
--kendo-color-primary-hover: var(--holiday-red-hover) !important;
--kendo-color-primary-active: var(--holiday-red-active) !important;
--kendo-color-primary-emphasis: rgba(179, 32, 45, 0.4) !important;
--kendo-color-primary-subtle: #f8dce0 !important;
--kendo-color-primary-subtle-hover: #f2c6cc !important;
--kendo-color-primary-subtle-active: #ecb0b8 !important;
--bs-primary: var(--holiday-red);
--bs-primary-rgb: 179, 32, 45;
--bs-primary-text-emphasis: #4a0d13;
--bs-primary-bg-subtle: #f8dce0;
--bs-primary-border-subtle: #ecb0b8;
--bs-link-color: var(--holiday-red);
--bs-link-hover-color: var(--holiday-red-active);
--bs-focus-ring-color: rgba(179, 32, 45, 0.25);
}
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
background-color: var(--holiday-cream);
}
a, .btn-link {
color: #006bb7;
color: var(--holiday-red);
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
background-color: var(--holiday-red);
border-color: var(--holiday-red-hover);
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem rgba(179, 32, 45, 0.5);
}
.content {
@@ -46,8 +80,39 @@ h1:focus {
content: "An error has occurred."
}
/* App.razor forces every `.container` to min-height:100vh for the
full-page screens outside the wizard; inside the wizard's own
viewport-constrained content pane that forces every step to be at
least a full viewport tall (and scroll), regardless of actual content. */
.k-wizard-content .container {
min-height: auto;
}
.sbWizard {
text-align: center;
border-radius: 0.5rem;
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.08);
border-top: 6px solid var(--holiday-red) !important;
margin-top: 1.5rem;
}
.sbWizard h1 {
color: var(--holiday-green);
}
/* Consistent "framed photo" treatment for the card/design/greeting preview
images, so they read as a curated set instead of loose product shots. */
.card-preview-img {
border-radius: 0.5rem;
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
border: 3px solid #fff;
outline: 1px solid #e9e2d2;
transition: transform 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.card-preview-img:hover {
transform: scale(1.02);
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.2);
}
.vertical-buttons {
@@ -58,3 +123,38 @@ h1:focus {
.block-buttons {
display: flex;
}
.order-summary {
max-width: 40rem;
background-color: var(--holiday-cream);
border: 1px solid var(--holiday-gold);
border-radius: 0.5rem;
padding: 1.25rem 1.5rem;
}
.order-summary dt {
color: var(--holiday-green);
font-weight: 600;
}
.order-summary dd {
margin-bottom: 0.5rem;
}
/* Step labels get squeezed into ~7 equal-width columns on the horizontal
stepper; below ~576px there isn't room for a single line, so let them
wrap onto two lines instead of ellipsis-truncating to an unreadable sliver. */
@media (max-width: 576px) {
.k-step-list-horizontal .k-step-text {
white-space: normal !important;
overflow: visible !important;
text-overflow: clip !important;
font-size: 0.65rem !important;
line-height: 1.05 !important;
}
.k-step-list-horizontal .k-step-link {
height: auto !important;
min-height: 3.5rem !important;
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 KiB

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

After

Width:  |  Height:  |  Size: 6.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 223 KiB