Conversation
- Add menu_type enum (regular/holiday) with compound unique index (week_id, menu_type), allowing one regular + one holiday menu per week - Add Setting.holiday_menu_id; Menu.current_holiday, open_for_orders! (no email), updated make_current!/current?/can_publish? for both types - orders_controller accepts menu_id param for holiday orders; render_current_order concern fetches holiday menu/order - show.json.jbuilder refactored to partials; adds holidayMenu/holidayOrder - Admin: menu_type select, holiday badge, open_for_orders action, _holiday_open partial with clear no-email messaging - Frontend: extract Layout.tsx, new MenuTabs.tsx (MUI Tabs, ARIA-compliant, New badge, handles null regular menu) and HolidayMenuTab.tsx - 22 new tests + Passover 2026 fixtures (178 runs, 0 failures) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 52c128c493
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def create | ||
| if current_user&.current_order | ||
| logger.warn "user=#{current_user.email} already placed an order. returning that order" | ||
| target_menu = params[:menu_id].present? ? Menu.find(params[:menu_id]) : Menu.current |
There was a problem hiding this comment.
Restrict
menu_id to active orderable menus
This accepts any menu_id from the request and only rejects when that menu is already past deadline, which means clients can create orders for menus that were never opened as current/holiday (e.g., future regular menus or unopened holiday menus) by posting directly to /orders.json. Because resources :menus, only: [:show] exposes menu IDs publicly, this bypasses the new open_for_orders! gating and can create unintended orders; menu_id should be validated against the currently orderable menus only.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- copy_from: don't copy limit=0 (sold-out state) to new menu — reset to nil so items start as available on the copied menu - Admin: week options now future-only (0..10 range); hide test email button for holiday menus with explanatory note instead - MenuTabs: warm bakery-themed styling, "Holiday" badge instead of "New" - CLAUDE.md: note to use jq for JSON parsing in shell Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use Raleway/Oswald fonts matching rest of site - Active color: brand purple #352c63, inactive: warm taupe #9e8c7a - Replace amber box badge with small Oswald uppercase "HOLIDAY" subtitle in site's rust accent color #d54a2c — no box, just typography - Bottom-align tabs so menu names share the same baseline - HOLIDAY label sits above the menu name Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the full-bleed two-column purple header approach with a simple tab bar (two equal bordered buttons) sitting above the original menu name header. Subscriber credits stay at the top, tabs below them, then the unchanged purple menu name. HideMenuNameContext retained in Contexts/Title for potential future use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.json: inherit AWS, HASHID_SALT from pipeline; default Stripe test keys - Disable email delivery in production when SendGrid credentials are absent - Add bin/seed_review_app to copy prod DB and restart dynos Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use render_current_order in orders#create so holiday order response returns the regular menu as primary (was returning holiday menu as both) - Always show Holiday badge on tab (was hidden after placing order) - Increase tab bar bottom margin from 4px to 16px - Remove unused HideMenuNameContext - Add Rails test for holiday order response and JS tests for badge Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the old per-pickup-day show page with /admin/pickup_lists/:date that aggregates orders from all pickup days on a given calendar date (e.g., regular + holiday menus with pickups on the same day). Includes orders tab and by-item tab. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update credit assertions (kyle: 23→20, ljf: 0→-2) to reflect new order_items consuming credits. Fix order count (kyle: 2→4). Switch passover preorder test to use jess (kyle already has a fixture order). Restore direct render in orders#create so marketplace orders appear in the JSON response — render_current_order's order_for_menu excludes marketplace orders by design. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
order_for_menu excludes marketplace orders (via .subscriber scope), so pass the just-created order directly instead of re-fetching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as create — pass the known order directly rather than re-fetching through order_for_menu. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: Two issues prevented holiday order updates from working. 1) Frontend: HolidayMenuTab managed its own isEditingOrder state but never reset it after a successful save. The Menu component fires onCreateOrder without awaiting the promise. Fix: wrap the handler to reset isEditingOrder on success. 2) Backend: render_current_order put all orders into @order (regular slot) regardless of menu type. A holiday order ended up in the wrong JSON slot. Fix: in create, move holiday orders to @holiday_order before rendering. Use ||= in render_current_order so pre-set ivars are preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of separate rows for regular and holiday bake lists, each day gets one card containing a labeled table per menu. Also show holiday menu link in the Menu panel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Holiday orders appear as a row in the existing Orders table. Holiday sales appear below regular sales in the same Sales panel. No more separate Holiday Orders/Holiday Sales panels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies exact cell values for subscribers (ordered=1, not_ordered=3), marketplace (0), and holiday (ordered=2). Confirms both sales tables show qty=0 because no fixtures have stripe_charge_amount — the identical values are correct, not a bug. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CreditItem.for_menu queries by week_id time range, so both menus in the same week return identical credit data. Credits are per-week not per-menu, so only show them in the regular sales section. Holiday sales section shows only marketplace orders. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to single row - Pickup list now uses ActiveAdmin's show page with proper tabs, table_for, and the existing _order_items partial (matching the original production view) - Date-based route (/admin/pickup_lists/:date) redirects to the ActiveAdmin pickup day show page - Sales panel uses a single table with Holiday as a row (like Orders panel) instead of rendering a separate holiday sales table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Credits used" column to Orders table (replaces separate panel) - Rename columns: Ordered→Orders, Skipped→Skip - Revert Sales partial to master style, show duplicate for holiday menu - Skip Credits row in holiday sales (credits are per-week, not per-menu) - Rename Credits to Credit Sales in sales table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Menu show page has a Danger Zone section (red header) between Orders and Emails - Delete button shown when menu has no orders, with confirmation dialog - "Show N orders" link when menu has orders, links to filtered orders page - Cleans up ActiveAdmin comments on delete, preserves PaperTrail versions - Styled with action-danger (red) and action-disabled (gray) button classes - Full workflow test: delete orders, then delete menu Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Block deleting the current regular or holiday menu - Test cascade: deleting menu destroys pickup_days and menu_items - Test sales partial: holiday menu hides Credit Sales row - Test current menu guard for both regular and holiday menus Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Test marketplace holiday order creation returns holidayOrder JSON slot - Add HolidayMenuTab JS tests: confirmation display, form display, and regression test for editing state reset after save - Pickup list overlapping dates already covered by existing fixtures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…er dashboard panels Credit balance panel now uses SQL-level filtering (ordered_within_days param) to show only subscribers who ordered in the last 30 days, reducing the list from 369 to ~22. Reorganized dashboard: credits row first, then special requests/new users/opt-in row. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Filters to/cc/bcc on all outgoing emails to admin-only allow list when REVIEW_APP is set. Shows banner on dashboard and menu email pages. Adds SendGrid credentials to app.json for review apps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consumer site: sticky purple banner at top of page Admin dashboard + menu email section: flash alert with context Email layouts: footer noting review app or local dev origin All banners hidden in production. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These vars should be set in the Heroku pipeline config and inherited by review apps. Marking them required blocks review app creation if they're not explicitly provided at creation time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copies AWS, HASHID_SALT, and SendGrid credentials from production to the review app before seeding the database. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Trims ahoy_events and ahoy_visits older than 90 days. Run daily via Heroku Scheduler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge agents.md into CLAUDE.md, simplify README with Heroku infrastructure docs (addons, scheduled jobs, review apps). Add scheduler and scheduler-monitor to app.json for auto-provisioning. Add bin/seed_local for pulling prod data locally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… copy_from limits test Show all weeks in the dropdown with annotations for which types already exist, instead of filtering by a single menu_type that goes stale on dropdown change. Add test verifying copy_from clears sold-out (0) limits to nil. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… slotting - Hide delete button for current menu, show message instead - Extract repeated holiday status_tag inline style to .holiday-tag CSS class - Add em-dashes for N/A cells in holiday orders row - Make orders#update explicitly slot holiday orders (match create path) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Complete ARIA tabs pattern: tabpanel, aria-controls, aria-labelledby - Add arrow-key navigation between tabs with focus management - Add :focus-visible outline for keyboard users - Bump tab font 0.85→0.95rem, badge 0.6→0.7rem for legibility - Fix badge color to match $motzi-red (#d5482c) - Widen tab gap 4→8px, border-radius 3→4px to match Bootstrap - Add overflow/ellipsis handling for long menu names on mobile - Mark HolidayBadge as aria-hidden (decorative) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Holiday menu support for Motzi — the long-awaited ability to run special pre-order menus (like Passover) alongside the regular weekly menu. Plus significant admin dashboard improvements.
What's New
Holiday Menus (ordering)
menu_typefield on menus:regularorholidayweek_id + menu_type)holidayMenu/holidayOrderin API response)/admin/pickup_list/:date) that aggregates orders across all menus sharing a pickup dateAdmin Dashboard Improvements
.holiday-tagCSS classDelete Menu Feature
Menu Form Improvements
copy_fromclears sold-out limits (0 → nil) so copied menus start freshConsumer UI Accessibility
role="tabpanel",aria-controls,aria-labelledbyon panels and tabs:focus-visibleoutline on tab buttonsaria-hidden(decorative)$motzi-red; border-radius aligned with Bootstrap defaultReview App Safety
app.jsonfor Heroku review apps with safe defaultsbin/seed_review_appscript seeds real production dataapp.jsonfor review appsAnalytics Cleanup
cleanup:trim_analyticsrake task trimsahoy_eventsandahoy_visitsolder than 90 daysDocs & Tooling
agents.mdintoCLAUDE.md(single source of truth for AI agents)README.mdwith Heroku infrastructure docs (addons, scheduled jobs, review apps)bin/seed_localscript to pull prod data for local developmentFiles Changed
70+ files changed, ~2800 insertions, ~290 deletions across:
Test Coverage
current_holiday,open_for_orders!, uniqueness constraints,copy_fromsold-out limitsReview App
https://motzi-pr-301.herokuapp.com — seeded with production data, emails delivered to admin users only.
🤖 Generated with Claude Code