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>
- uploadSavedPage.cfm: sanitize extracted files (whitelist safe extensions,
delete symlinks) to protect against malicious content from infected sites
- analyzeMenuUrl.cfm: detect local temp URLs and read directly from disk,
bypassing Playwright for faster processing of saved pages
- saveWizard.cfm: delete temp folder immediately after wizard completes
instead of waiting for 1-hour auto-cleanup
- setup-wizard.html: track temp folder ID and pass to saveWizard for cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For Cloudflare-protected sites, users can now:
1. Save the page from their browser (Webpage, Complete)
2. ZIP the HTML and assets folder
3. Upload the ZIP in the wizard
4. Server extracts to temp folder, Playwright scans local copy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Backend now accepts either url or html content in request body
- Frontend adds HTML file upload option below URL input
- Useful when websites block the crawler (403 errors)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove Task Categories section from Task Admin page (deprecated)
- Simplify HUD getCategoryColor() to use TaskTypeColor directly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show a modal with file input and preview
- Uses alert() instead of toast for error messages (more visible on mobile)
- Preview shows selected image before upload
- Submit button with loading state
- Keeps old uploadPhoto function for compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use persistent file input instead of dynamically created one
- Store pending upload info in sessionStorage for mobile camera flow
- Use simpler accept="image/*" for better mobile compatibility
- Handle case where page context is lost after camera returns
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HEIC/HEIF support for iPhone camera photos
- Make frontend file type validation more permissive for mobile browsers
- Add 'capture' attribute to prefer rear camera on mobile
- Include actual file extension in error messages for debugging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The API returns ServicePointID but portal.js was using sp.ID which was undefined.
Changed all sp.ID references to sp.ServicePointID.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of auto-selecting first business, redirect to login.html
which shows the business selection dropdown for users with multiple businesses.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix menu builder dropdown showing empty names (return MenuName instead of Name)
- Add default menu selection (setDefault action, DefaultMenuID in getForBuilder)
- Fix createPaymentIntent column names for dev schema (ID, StripeAccountID, etc.)
- Fix menu-builder favicon and remove redundant business label
- Comment out Tabs/Running Checks feature for launch (HTML + JS)
- Comment out Service Point Marketing/Grants feature for launch (HTML + JS)
- Add testMarkPaid.cfm for testing orders without Stripe webhooks
- Task API updates for worker payout ledger integration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Menu builder UI improvements
- Portal CSS and JS updates
- Station assignment updates
- Add business tabs update endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Converts 200+ endpoint files to use queryTimed() wrapper which tracks
DB query count and execution time. Restores perf dashboard files that
were accidentally moved to _scripts/. Includes portal UI updates.
Grant-based system allowing businesses to share service points with
other businesses. Includes grant CRUD API, time/eligibility/economics
policies, enforcement at cart creation and order submit, Stripe payment
routing for owner fees, and portal UI for managing grants.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move business card to top, remove logout button and sidebar-footer,
add missing Task Admin nav item.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Save FirstName to localStorage on login (both OTP and password paths).
Portal reads it back and displays the first letter in the user avatar.
Falls back to 'U' if no name is stored. Cleared on logout.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Business info card now sits between the Payfrit logo and the nav links.
Sidebar footer removed entirely.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
User icon dropdown now has: Settings, Switch Business, Add New Business,
Logout. Removed redundant logout from sidebar footer.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Brand color: add # prefix when loading from DB (stored without #,
CSS needs it for backgroundColor)
- Header upload: delete destination file before rename to prevent
collision when re-uploading same extension
- Header preview: prepend BASE_PATH to image URL for local dev
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>