Add BrandColorLight to menu API and setup wizard

- items.cfm: return BrandColorLight in menu response
- saveWizard.cfm: save BrandColorLight during business creation
- setup-wizard.html: second color picker for light brand color

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-03-05 19:24:45 -08:00
parent 771f70f2f3
commit 1568686ff1
3 changed files with 41 additions and 8 deletions

View file

@ -558,7 +558,7 @@
<cfset brandColor = "">
<cfset headerImageUrl = "">
<cfset qBrand = queryTimed(
"SELECT BrandColor AS BusinessBrandColor, TaxRate, PayfritFee, HeaderImageExtension, SessionEnabled FROM Businesses WHERE ID = ?",
"SELECT BrandColor AS BusinessBrandColor, BrandColorLight AS BusinessBrandColorLight, TaxRate, PayfritFee, HeaderImageExtension, SessionEnabled FROM Businesses WHERE ID = ?",
[ { value = BusinessID, cfsqltype = "cf_sql_integer" } ],
{ datasource = "payfrit" }
)>
@ -577,6 +577,10 @@
<cfif len(trim(qBrand.BusinessBrandColor))>
<cfset brandColor = left(qBrand.BusinessBrandColor, 1) EQ chr(35) ? qBrand.BusinessBrandColor : chr(35) & qBrand.BusinessBrandColor>
</cfif>
<cfset brandColorLight = "">
<cfif len(trim(qBrand.BusinessBrandColorLight))>
<cfset brandColorLight = left(qBrand.BusinessBrandColorLight, 1) EQ chr(35) ? qBrand.BusinessBrandColorLight : chr(35) & qBrand.BusinessBrandColorLight>
</cfif>
<cfif len(trim(qBrand.HeaderImageExtension))>
<cfset headerImageUrl = "/uploads/headers/#BusinessID#.#qBrand.HeaderImageExtension#">
</cfif>
@ -588,6 +592,7 @@
"COUNT": arrayLen(rows),
"SCHEMA": newSchemaActive ? "unified" : "legacy",
"BRANDCOLOR": brandColor,
"BRANDCOLORLIGHT": brandColorLight,
"HEADERIMAGEURL": headerImageUrl,
"TAXRATE": val(businessTaxRate),
"PAYFRITFEE": val(businessPayfritFee),

View file

@ -169,12 +169,16 @@ try {
// Extract tax rate (stored as decimal, e.g. 8.25% -> 0.0825)
bizTaxRate = structKeyExists(biz, "taxRatePercent") && isSimpleValue(biz.taxRatePercent) ? val(biz.taxRatePercent) / 100 : 0;
// Extract brand color (6-digit hex without #)
// Extract brand colors (6-digit hex without #)
bizBrandColor = structKeyExists(biz, "brandColor") && isSimpleValue(biz.brandColor) ? trim(biz.brandColor) : "";
// Ensure it's a valid 6-digit hex (remove # if present)
bizBrandColor = reReplace(bizBrandColor, "^##?", "");
if (!reFind("^[0-9A-Fa-f]{6}$", bizBrandColor)) {
bizBrandColor = ""; // Invalid format, skip it
bizBrandColor = "";
}
bizBrandColorLight = structKeyExists(biz, "brandColorLight") && isSimpleValue(biz.brandColorLight) ? trim(biz.brandColorLight) : "";
bizBrandColorLight = reReplace(bizBrandColorLight, "^##?", "");
if (!reFind("^[0-9A-Fa-f]{6}$", bizBrandColorLight)) {
bizBrandColorLight = "";
}
// Create address record first (use extracted address fields) - safely extract as simple values
@ -237,8 +241,8 @@ try {
// Create new business with address link and phone
queryTimed("
INSERT INTO Businesses (Name, Phone, UserID, AddressID, DeliveryZIPCodes, CommunityMealType, TaxRate, BrandColor, AddedOn)
VALUES (:name, :phone, :userId, :addressId, :deliveryZips, :communityMealType, :taxRate, :brandColor, NOW())
INSERT INTO Businesses (Name, Phone, UserID, AddressID, DeliveryZIPCodes, CommunityMealType, TaxRate, BrandColor, BrandColorLight, AddedOn)
VALUES (:name, :phone, :userId, :addressId, :deliveryZips, :communityMealType, :taxRate, :brandColor, :brandColorLight, NOW())
", {
name: bizName,
phone: bizPhone,
@ -247,7 +251,8 @@ try {
deliveryZips: len(zip) ? zip : "",
communityMealType: communityMealType,
taxRate: { value: bizTaxRate, cfsqltype: "cf_sql_decimal" },
brandColor: { value: len(bizBrandColor) ? bizBrandColor : javaCast("null", ""), cfsqltype: "cf_sql_varchar", null: !len(bizBrandColor) }
brandColor: { value: len(bizBrandColor) ? bizBrandColor : javaCast("null", ""), cfsqltype: "cf_sql_varchar", null: !len(bizBrandColor) },
brandColorLight: { value: len(bizBrandColorLight) ? bizBrandColorLight : javaCast("null", ""), cfsqltype: "cf_sql_varchar", null: !len(bizBrandColorLight) }
}, { datasource: "payfrit" });
qNewBiz = queryTimed("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });

View file

@ -2024,6 +2024,18 @@
document.getElementById('bizBrandColorHex').value = colorVal.replace('#', '').toUpperCase();
}
function syncBrandColorLight(hexInput) {
let hex = hexInput.value.replace(/[^0-9A-Fa-f]/g, '').toUpperCase();
if (hex.length === 6) {
document.getElementById('bizBrandColorLight').value = '#' + hex;
}
}
function onBrandColorLightPick() {
const colorVal = document.getElementById('bizBrandColorLight').value;
document.getElementById('bizBrandColorLightHex').value = colorVal.replace('#', '').toUpperCase();
}
// Step 1: Business Info
async function showBusinessInfoStep() {
updateProgress(2);
@ -2138,6 +2150,14 @@
<span style="font-size:11px;color:var(--gray-400);">Used for menu accents</span>
</div>
</div>
<div class="extracted-value editable">
<label style="font-size:12px;color:var(--gray-500);display:block;margin-bottom:4px;">Brand Color Light</label>
<div style="display:flex;align-items:center;gap:12px;">
<input type="color" id="bizBrandColorLight" value="#${biz.brandColorLight || 'F5F5F5'}" style="width:50px;height:36px;padding:2px;border:1px solid var(--gray-300);border-radius:6px;cursor:pointer;" onchange="onBrandColorLightPick()">
<input type="text" id="bizBrandColorLightHex" value="${biz.brandColorLight || ''}" placeholder="F5F5F5" maxlength="6" style="width:80px;font-family:monospace;" oninput="syncBrandColorLight(this)">
<span style="font-size:11px;color:var(--gray-400);">Light tint for card backgrounds (optional)</span>
</div>
</div>
<div class="extracted-value editable">
<label style="font-size:12px;color:var(--gray-500);display:block;margin-bottom:4px;">Business Hours</label>
<div style="font-size:11px;color:var(--gray-400);margin-bottom:4px;">12:00 PM = Noon &nbsp;&bull;&nbsp; 12:00 AM = Midnight</div>
@ -2233,9 +2253,11 @@
}
// Update stored data with any edits
// Get brand color from hex input (without #)
// Get brand colors from hex inputs (without #)
let brandColor = document.getElementById('bizBrandColorHex').value.replace(/^#/, '').toUpperCase();
if (!/^[0-9A-F]{6}$/.test(brandColor)) brandColor = 'E74C3C'; // Default if invalid
let brandColorLight = (document.getElementById('bizBrandColorLightHex').value || '').replace(/^#/, '').toUpperCase();
if (brandColorLight && !/^[0-9A-F]{6}$/.test(brandColorLight)) brandColorLight = '';
config.extractedData.business = {
name: document.getElementById('bizName').value,
@ -2246,6 +2268,7 @@
phone: document.getElementById('bizPhone').value,
taxRatePercent: parseFloat(document.getElementById('bizTaxRate').value) || 0,
brandColor: brandColor,
brandColorLight: brandColorLight,
hoursSchedule: hoursSchedule // Send the structured schedule instead of the raw hours string
};