Changed t.ID to t.TaskID in three places - the API returns TaskID
not ID, so filtering and lookups were failing.
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>
- sendLoginOTP.cfm: Accept Email, Phone, or Identifier field
Sends OTP via SMS for phone, email for email addresses
- verifyEmailOTP.cfm: Accept phone numbers for verification
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For businesses using beacon sharding:
- beacons/list.cfm now returns ServicePoints with BeaconMinor as beacons
- assignments/list.cfm now shows sharding assignments (SP + Minor)
- Both APIs include USES_SHARDING flag and sharding info
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The lookup API now handles two formats:
1. Sharding: { "Beacons": [{ "UUID", "Major", "Minor" }] }
Resolves via BeaconShards -> Businesses.BeaconMajor -> ServicePoints.BeaconMinor
2. Legacy: { "UUIDs": ["..."] }
Resolves via old Beacons table
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Modifiers are saved with CategoryID=0 and ParentItemID pointing to their
parent item. The query was filtering by CategoryID IN (visible categories)
which excluded all modifiers.
Changed to: (CategoryID IN (visible) OR (CategoryID=0 AND ParentItemID>0))
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>
- Listen to browser online/offline events
- Check navigator.onLine before API calls
- Update status indicator immediately when connection changes
- Auto-refresh when coming back online
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
User-uploaded content and log files should not be version controlled:
- Added uploads/ and *.log to .gitignore
- Removed uploads/ directory from tracking (files remain on disk)
- Removed api/menu/saveFromBuilder.log from tracking
This prevents git reset --hard from overwriting user content during deploys.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- getCart.cfm: Include TaxRate from Businesses table
- getOrCreateCart.cfm: Include TaxRate from Businesses table
- items.cfm: Include TaxRate in menu response for cart calculation
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>
- profile.cfm now returns AvatarUrl in USER object
- avatar.cfm now updates Users.ImageExtension after successful upload
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When both OrderID and UserID are 0, dont join to User 0 (Payfrit Network).
Instead return no customer info, letting the app show Guest.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
COALESCE treats 0 as valid, so Order.UserID=0 was matching User 0
(Payfrit Network) instead of falling back to Task.UserID.
Use NULLIF to convert 0 to NULL before the fallback.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For order-based tasks, the customer comes from Order.UserID.
For standalone tasks without an order, fall back to Task.UserID.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Store UserID when creating service bell tasks
- Return CustomerID and CustomerName in listPending and listMine
- Join Users table to fetch customer first/last name
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use COALESCE(t.ServicePointID, o.ServicePointID) in JOIN
- Add ServicePointID to JSON response
- Fixes service bell tasks showing table name
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Redesign KDS with HUD-matching dark theme (pure black background)
- Header styling identical to HUD: position, font, clock format
- Status indicator moved to bottom-right corner like HUD
- Remove business ID config - now uses portal localStorage only
- Keep station toggle functionality
- Fix updateStatus.cfm: use correct column names for dev DB
(sp.Name instead of sp.ServicePointName, sp.ID instead of sp.ServicePointID)
- Use relative API URL instead of hardcoded production URL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ServicePointID to INSERT statement for service bell tasks
- Fix tt_TaskTypes query to use ID instead of tt_TaskTypeID
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add beacon-sharding API endpoints for scalable iBeacon addressing
(64 shard UUIDs × 65k businesses = ~4.2M capacity)
- Fix callServer.cfm to save UserID when creating Call Server tasks
- Fix getDetails.cfm to return customer info from Task.UserID when
Order.UserID is null (for tasks without orders)
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>
- Replace tt_OrderTypes JOIN with CASE statement (table casing on Linux)
- Fix key mismatches: Name->BusinessName, UUID->OrderUUID, StatusID->OrderStatusID
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>