PHP API is now deployed on both dev and biz servers with PHP-FPM.
Admin endpoints (quickTasks, scheduledTasks) remain .cfm as they
haven't been ported yet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Another tab doing the PHP migration renamed all API endpoint references
from .cfm to .php, but the PHP endpoints aren't deployed yet. Reverted
all references back to .cfm so the wizard and portal work again.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Combined HTML from multiple sub-pages was too large. Now strips all HTML
tags and keeps only text content for Claude extraction. Also strips
nav/header/footer from sub-pages to remove duplication. Bumped Claude
API timeout from 120s to 300s. Updated wizard message to say 1-3 minutes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
parseHoursString expected a string but Claude AI sometimes returns
structured hours data as an object. Now normalizes to string first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip common suffixes like "Order pickup and delivery" and embedded
street addresses from business names. Clean city field when it contains
state/zip/country (e.g. "Santa Monica, CA 90405, USA" → "Santa Monica").
Fixes applied in both CFML parser and JS frontend as safety net.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Feature cancelled — modifier wording handles the use case instead.
Removes IsInvertedGroup from SELECTs, JSON responses, RemovedDefaults
computation, and KDS/portal display logic. DB column left in place.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The JSON-LD fast path only got items/categories/prices but no modifiers.
Removing it lets Uber Eats pages fall through to Claude AI extraction
which handles modifiers like every other platform.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Warning to disable ad blockers before saving pages for import
- Listed supported platforms with what each extracts (Toast, Grubhub,
DoorDash, Uber Eats, and fallback AI extraction)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed IsInvertedGroup toggle and badge from menu builder UI
- Fixed saveFromBuilder.cfm not updating Name for template modifiers
(only selection rules were saved, name changes were silently lost)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Application.cfm requires request.BusinessID from session or header.
The fetch was only sending it in the POST body which the auth layer
doesn't read.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- showToast → toast (correct method name) across all settings methods
- Clear onchange before setting .checked to prevent save during load
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire onchange listener via JS instead of inline attribute,
matching the hiring toggle pattern. The zero-sized hidden
checkbox wasn't firing inline onchange reliably.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses the native EyeDropper API (Chrome/Edge) to pick colors from
anywhere on screen. Button only shows in supported browsers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When enabled on a modifier group, KDS and cart only show removed
defaults (e.g., "NO Mustard") instead of listing all selected items.
Useful for groups where all options are checked by default.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse JSON-LD structured menu data from saved Uber Eats pages
(categories, items, prices, descriptions, business info)
- Show save-and-upload instructions when user pastes Uber Eats URL
- Always show header image upload step (was skipped for URL imports)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getOrCreateCart: only require ServicePointID for dine-in (OrderTypeID=1)
- get.cfm + items.cfm: return OrderTypes from Businesses table
- saveOrderTypes.cfm: new endpoint to save business order type config
- KDS: add PICKUP/DELIVERY badges on order cards
- Portal: add Order Types toggle card in settings (Dine-In always on, Takeaway toggle)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed from cover/fixed-height to contain/aspect-ratio 3:1 so the
full 1200x400 header image is visible without cropping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
Updated the portal settings brand color picker to show both dark
and light colors. Light swatch shown alongside dark swatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New BrandColorLight column on Businesses table. Menu builder cards
(categories, subcategories, items) get a very subtle tint from the
light brand color. White when no color is set. Brand color picker
now has both dark and light fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Station assignment was a standalone page with no sidebar. Added the
same portal sidebar so users can navigate between pages. Also added
Stations link to menu-builder sidebar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds button in the outline modal to toggle modifier group display
under each item. Each group shows a + to expand into full options
with prices. Useful for debugging modifier assignments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the conditional out of the nested template literal to avoid
parsing issues with arrow functions inside backtick strings. Also
skip empty mod-groups divs on items without modifiers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Outline button reveals modifier groups under each item with a +
expand button to drill into individual options and prices. Helps
debug imported menus before saving.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For URL imports (Toast, Grubhub, etc.) there's no header image
to show, so skip straight from business info to categories
instead of showing an empty "Choose Image / Skip" prompt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API returns Name, Price, ParentItemID, CategoryID, StationID but JS
was referencing ItemName, ItemPrice, ItemParentItemID, etc. causing
all items to be filtered out and not displayed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New endpoints: save.cfm (combined add/update) and delete.cfm
(soft-delete with item unassignment). Registered in Application.cfm.
Portal station-assignment page now uses real API calls for add,
edit, and delete instead of client-side-only prompt(). Fixed key
naming mismatch (StationName/StationColor → Name/Color) so the
page works with real API data. Removed hardcoded demo fallbacks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Constrain main-content to 100vh and builder-wrapper to flex: 1
so the height chain propagates correctly and the properties panel
scrolls within the viewport instead of extending off screen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Properties panel was extending off screen due to missing min-height: 0
on flex containers. Made Properties header sticky so it floats as you
scroll through long modifier lists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Subcategories shared expandedCategoryId with parent categories,
so clicking a subcategory collapsed the parent. Added separate
expandedSubCategoryId state so subcategories expand independently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows subcategory count as a separate indented row beneath categories
when subcategories are present.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed from fixed 120px height to aspect-ratio 3:1 to match the
recommended 1200x400 dimensions, preventing heavy cropping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- analyzeMenuUrl.cfm: Detect subcategories from Toast subgroups and
Claude API responses, preserve hierarchy with parentCategoryName
- setup-wizard.html: Display subcategories indented under parents
throughout wizard flow (categories step, items review, summary, preview)
- menu-builder.html: Show subcategories nested in outline modal view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- saveCategory.cfm: Accept ParentCategoryID, enforce max 2-level nesting
- items.cfm: Include ParentCategoryID on virtual category rows for Android
- getForBuilder.cfm: Return ParentCategoryID in builder API response
- saveFromBuilder.cfm: Persist ParentCategoryID on save, track JS-to-DB id mapping
- saveWizard.cfm: Two-pass category creation (parents first, then subcategories)
- menu-builder.html: Parent category dropdown in properties, visual nesting in canvas,
add subcategory button, renderItemCard() extracted for reuse
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create tt_StaffRoles lookup table (Staff, Manager, Admin)
- Add RoleID column to Employees table (default: Staff)
- Wire portal role dropdown to addTeamMember API
- Return RoleName in team list and RoleID to Android
- Skip worker payout ledger and cash_debit for Manager/Admin roles
on cash task completion (they collect on behalf of the restaurant)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New api/tabs/ directory with 13 endpoints: open, close, cancel, get, getActive,
addOrder, increaseAuth, addMember, removeMember, getPresence, approveOrder,
rejectOrder, pendingOrders
- New api/presence/heartbeat.cfm for beacon-based user presence tracking
- New cron/expireTabs.cfm for idle tab expiry and presence cleanup
- Modified submit.cfm for tab-aware order submission (skip payment, update running total)
- Modified getOrCreateCart.cfm to auto-detect active tab and set TabID on new carts
- Modified webhook.cfm to handle tab capture events (metadata type=tab_close)
- Modified businesses/get.cfm and updateTabs.cfm with new tab config columns
- Updated portal tab settings UI with auth amounts, max members, approval toggle
- Added tab and presence endpoints to Application.cfm public allowlist
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The addEventListener wasn't firing (likely cached JS). Added inline
onclick as reliable fallback and flexbox centering for the SVG icon.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
b.Minor is 0 for the first beacon which is falsy in JS.
Changed to null check so Minor: 0 displays correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The refresh button in the top bar had no click handler attached.
Now it reloads the current page data when clicked.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The escaped backticks (\`) were causing "invalid escape sequence" error,
breaking the entire script and making the Upload Files button non-functional.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When business info step loads with a ZIP code, automatically looks up
the combined sales tax rate and pre-fills the field. User can still
edit if needed. Field gets light green background to indicate auto-fill.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Items were being grouped only by known categories. If the category
array was empty or didn't include an item's category, those items
never got checkboxes rendered, causing confirmItems() to filter
them all out.
Now collects unassigned items and groups them by their category
name (or 'Menu' as fallback).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log sample imageUrls to console to debug why upload step is shown.
Also handle protocol-relative URLs (//domain.com/...).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Items from Toast menus have CDN URLs (https://img.cdn4dd.com/...) which
saveWizard.cfm will download automatically. No need to prompt user
to upload images when remote URLs are already present.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>