10 Commits

Author SHA1 Message Date
f969e5d242 feat: configurable booking lead time in admin (default 48h)
Adds leadTimeHours to HoursConfig. Slot generation, calendar minDate,
and pickup disabled-date precomputation all read from the config.
Admin hours page has a new input to adjust it without a redeploy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 07:48:13 -04:00
bb6c8a03a7 fix: calendar newlines, admin delivery window setting
CalDAV: joins were using literal '\n' strings which icalEscape then
double-escaped the backslash, so calendar entries showed raw \n. Now
joins use real newline chars which icalEscape converts correctly.

Added deliveryWindowMinutes to HoursConfig (default 60 min). The
checkout route reads this at request time to set both the Square
deliveryWindowDuration and the customer email arrival window. Admin
hours page now has a number input to configure it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 10:57:37 -04:00
be7f98a347 Add admin backup and restore for all config files
Download button exports item-overrides, delivery-rates, categories-display,
occasions, hours, and vinyl-config as a single JSON file. Restore button
applies a previously downloaded backup (skips vinyl-config to avoid
overwriting it). Both accessible from the admin header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 23:09:34 -04:00
1dc8a087b6 Add vinyl configurator feature and admin sync from balloons-shop
- vinyl-config route + data file for shape/font/pricing config
- CatalogItem: vinylEnabled, vinylPromo fields
- ItemOverride: vinylEnabled, vinylPromo fields
- catalog route: applies vinylEnabled/vinylPromo overrides
- ColorPicker: full vinyl configurator UI (shape picker, text/font, pricing)
- CartContext: vinyl cart fields (vinylText, vinylFontId, vinylShape, etc.)
- CartDrawer: vinyl line items flatMap (shape balloon + custom vinyl service)
- admin/items route: synced more-complete version from balloons-shop
- admin page: vinyl configurator and promo note checkboxes in ItemEditor

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 17:01:28 -04:00
27093bcd54 fix: multi-category checkboxes in admin + requires-delivery toggle
- Category selector replaced with checkboxes — items can now be
  assigned to multiple categories directly in admin (not just Square).
  Each category shows a "Square" label if it came from the Square
  assignment. Saves as categoriesOverride[] (array of category names).
- categoriesOverride takes precedence over old categoryOverride in the
  catalog route; old overrides still work as fallback.
- Requires-delivery toggle and custom rate fields were already in the
  code but needed container rebuild to appear — no logic change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:44:00 -04:00
0ea1b98a1f feat: required delivery toggle with custom rates per item
Items can now be marked as "requires delivery" in admin — these items
cannot be picked up and must be delivered (and struck).

- Admin item editor: "Requires delivery" checkbox + custom base/per-mile
  rate fields that appear when the toggle is on
- ProductCard: "Delivery & setup required" note on the card
- CartDrawer: pickup toggle is hidden and replaced with an explanation
  when any cart item requires delivery; the quote call passes the
  item's custom rate override (highest base + highest per-mile wins
  when multiple requires-delivery items are in the cart)
- delivery-quote API: accepts optional rateOverride to apply per-item
  pricing on top of the inferred tier

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:31:29 -04:00
623b237826 feat: multi-category items and fix new items not appearing
Items can now belong to multiple Square categories and appear in all
matching tabs (e.g. a Mother's Day balloon also shows under Easter).

Also fixes new items not appearing when the Square account has no
"online" category — previously this caused zero items to load; now
it falls back to showing all items.

Changes:
- CatalogItem gains categories[] + categoryLabels[] (multi-category)
- square.ts collects all non-skip categories per item; "online" filter
  is now optional (show all if category doesn't exist in Square)
- catalog/route.ts propagates categoryOverride into categories[0]
- FeaturedProducts: tabs and filter use the full categories array
- Admin CategoryDisplayEditor sees all categories from multi-cat items

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 15:39:31 -04:00
84ab6bef2d feat: featured items — admin toggle, badge, sorted to top
- Add featured to ItemOverride so it can be set per-item in admin
- Catalog API applies the override and sorts featured items before
  non-featured (within each group, sortOrder still applies)
- ProductCard shows a teal Featured badge on the image when featured
  and not sold out
- Admin item editor has a  Featured checkbox beside Hidden

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 14:21:33 -04:00
e95ec68931 feat: admin color availability filter per item
- Add disabledColors field to ItemOverride and CatalogItem
- Propagate through catalog API applyOverrides
- ColorPicker filters disabled colors out before showing to customers
- New AdminColorFilter modal: same collapsible family layout and balloon
  swatches as the customer view; click to hide/show individual colors;
  Enable all / Disable all shortcuts; badge shows count of hidden colors
- Button appears in the color limits section for color-enabled items

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 09:00:32 -04:00
50680a323f Major overhaul: shared nav, admin improvements, email enhancements, routing fixes
Navigation & layout
- Replace per-page hardcoded nav/footer with shared nav.js (client-side injection)
- Add nginx reverse proxy back to docker-compose for clean localhost routing
- Rename /color-picker/ to /color/ across nav, directory, and references

eStore admin
- Add variation hiding controls (mirrors existing modifier hiding)
- Add delivery rate editor (base fee + per-mile per tier, persisted to data/)
- Fix all missing BASE prefix on fetch calls (admin PATCH/DELETE, availability, slots, colors)
- Mount estore/data/ as a Docker volume so admin config survives rebuilds

Booking & calendar
- Set pickup calendar events to TRANSPARENT (free) so they don't block delivery slots
- Skip CANCELLED events in busy-time calculation
- Re-check slot availability at checkout before charging (409 on conflict)

Phone & email validation
- Auto-format phone as (XXX) XXX-XXXX as user types
- Require exactly 10 digits; tighten email regex

Confirmation emails (store alert + customer)
- Full item detail per line: name, price, add-ons, colors, note
- Charges breakdown: subtotal, delivery fee, tax, total
- Delivery window: simplified M/D/YY h:mm – h:mm AM/PM format
- .ics calendar attachment on customer confirmation

Delivery rates
- Extract configurable rates to delivery-rates.ts (server-only, no fs in client bundle)
- calcDelivery() accepts optional rates param; delivery-quote route passes configured rates

Content
- Change all "40+ latex colors" references to "70+"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 21:14:06 -04:00