Explain why a listing can't join a package (and a few other blocked combinations) - #1770
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughPackage restriction validation now reports specific blocking reasons across shared and admin flows. English error messages, tests, restriction TODOs, and explanatory UI copy were updated; no other functional areas changed. ChangesPackage restriction validation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant AdminRequest
participant GroupValidation
participant PackageMembership
participant ErrorLocalization
AdminRequest->>GroupValidation: validate package or child relationship
GroupValidation->>PackageMembership: determine blocking reason
PackageMembership->>ErrorLocalization: format reason-specific message
ErrorLocalization-->>AdminRequest: return validation error
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
When a listing can't be part of a package, the site used to show one catch-all message that listed every possible reason at once and never said which of the operator's listings was the problem. Split it into three specific messages that name the offending listing and give the one reason that applies — pay-what-you-want, an add-on of another listing, or (on a hidden package) a listing that offers its own add-ons — each with the exact fix. Do the same for the two "add children" conflicts (a hidden-package member gaining children, or picking a package member as a child), which shared the same vague message, and for the "daily add-on needs a daily parent" rule, which now explains that a daily add-on takes its date and length from its parent. The package-membership rule itself was written out three times across the group save, the listing save, and the catalog importer; this pulls it into one shared helper so the rule and its wording can't drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MD8aVv9TPPMx1rH3NgkhqN
Two small, informative notes so people aren't left guessing: - The payment-provider chooser now says that switching providers keeps your other provider's saved key (it just stops using it), so operators don't think entering a second provider wiped the first. - The free-text question note now says a free-text question can't change the price, since a price modifier attaches to a chosen answer and a typed answer has none. Also records the remaining restrictions-audit follow-ups in TODO.md — the bigger rule-relaxations and the message/UX fixes that need more than a copy tweak (e.g. flagging SumUp as unavailable for the site currency, which needs the currency threaded into the settings page). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MD8aVv9TPPMx1rH3NgkhqN
0877ce8 to
eca223d
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/shared/package-membership.test.ts`:
- Around line 79-116: Update the tests for packageMemberBlockError and
packageChildEdgeError to assert each complete expected localized message with
exact equality instead of multiple toContain checks. Preserve the existing
reason-specific inputs and expected user-facing wording for all five cases.
In `@test/ui/templates/admin/questions.test.ts`:
- Around line 212-216: Strengthen the assertions in the admin question rendering
test by checking the complete explanatory text, including both the absence of
answer options and the selected-answer rationale, rather than asserting only the
price conclusion. Replace the broad presence checks near the existing html
assertions with an exact or sufficiently specific assertion that covers the full
explanation while preserving the existing no-form assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: dc4b189e-3645-4c06-acdb-16abe628c142
📒 Files selected for processing (17)
TODO.mdsrc/features/admin/api.tssrc/features/admin/catalog-transfer/import.tssrc/features/admin/groups.tssrc/features/admin/listings-parents.tssrc/locales/en/errors.jsonsrc/locales/en/listings-table.jsonsrc/locales/en/settings.jsonsrc/shared/db/groups.tssrc/shared/listings-actions.tssrc/shared/package-membership.tssrc/ui/templates/admin/questions.tsxtest/lib/server-group-packages.test.tstest/shared/db/listing-parents.test.tstest/shared/listings-actions.test.tstest/shared/package-membership.test.tstest/ui/templates/admin/questions.test.ts
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/features/admin/catalog-transfer/import.ts`:
- Line 20: Move the reusable DB-backed packageMembersError validation helper out
of the groups route module into a neutral validation module. Update both the
groups route and the catalog import flow to import it directly from the new
module, preserving its current behavior and avoiding route-to-route coupling.
In `@src/features/admin/groups.ts`:
- Around line 97-104: Replace the imperative for...of scan in the
listing-selection flow with the repository’s curried `#fp` find or reduce
composition. Preserve packageMemberBlock evaluation order, return the first
truthy block with its listing, and retain the existing null result when no
listing matches.
In `@test/lib/server-group-packages.test.ts`:
- Line 600: Replace the partial body.error assertions in the server-group
package tests, including the corresponding checks around lines 624, 644, and
677, with exact comparisons against the appropriate localized error or flash
message. Use the existing localization symbols or complete structured response
expected by each scenario, while preserving the current test setup and behavior.
In `@test/shared/db/listing-parents.test.ts`:
- Around line 302-303: Strengthen the assertion in the daily-direction error
test by comparing the complete localized error message instead of checking only
the substring “takes its date and length from the parent.” Preserve the existing
error setup and assert the full stable message, or all stable structured fields
if the error is structured.
In `@TODO.md`:
- Around line 639-644: Update the TODO entry describing validateCalcValue so its
classification matches the document’s stated policy: either explicitly mark the
>100% surcharge rejection as an intentional restriction and remove the
bug-fix/workaround language, or classify it consistently as a known correctness
bug. Keep the behavior recommendation aligned with that classification.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bef247c2-8940-4d4a-8ab2-1e1ee171253f
📒 Files selected for processing (17)
TODO.mdsrc/features/admin/api.tssrc/features/admin/catalog-transfer/import.tssrc/features/admin/groups.tssrc/features/admin/listings-parents.tssrc/locales/en/errors.jsonsrc/locales/en/listings-table.jsonsrc/locales/en/settings.jsonsrc/shared/db/groups.tssrc/shared/listings-actions.tssrc/shared/package-membership.tssrc/ui/templates/admin/questions.tsxtest/lib/server-group-packages.test.tstest/shared/db/listing-parents.test.tstest/shared/listings-actions.test.tstest/shared/package-membership.test.tstest/ui/templates/admin/questions.test.ts
Responds to the automated review on the PR: - Move packageMembersError (and its firstUnpackageableMember helper) from the admin groups route module into #shared/db/groups.ts, next to its sibling packageChildEdgeConflict, so the catalog importer no longer reaches into a route module for it. - Replace the imperative for...of member scan with #fp mapNotNullish, per the repo's "prefer curried #fp utilities over loops" guideline. - Tighten the package/daily/child-edge tests to assert the complete localized message (exact equality) instead of substring checks, and add the causal clause to the free-text-question rendering assertion. - Reword the TODO restrictions-audit intro so the percentage-surcharge cap is consistently described as a latent bug rather than deliberate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MD8aVv9TPPMx1rH3NgkhqN
Captures the recurring "reject if any of N reasons, tell the user which, sometimes list all" pattern surfaced by the package-restriction work, with an honest assessment: the i18n keys and the existing EDGE_ERROR_RULES / CAPACITY_RULES tables already cover most of it, a global error-code framework is not worth building, and the one small win worth having is a user_error vs invariant_violation tag so money-integrity cases like refund_not_recorded can reach Sentry without burying it in expected validation noise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MD8aVv9TPPMx1rH3NgkhqN
Brings in #1770 (package combination messages). Kept both TODO.md follow-up sections; settings.json auto-merged with the copy changes intact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J1ZyDipwPBE9vSbgkb8ziT
Why
I went looking for every place the site refuses a combination someone might reasonably expect to work — the "why can't I select this?" moments that turn into support queries — and checked whether each one has a genuinely unavoidable reason or is just poorly explained. This PR ships the clearest wins where the rule is fine but the message left people guessing. The rest are written up in
TODO.md.What changed
Packages now tell you which listing is the problem, and why.
Before, adding an incompatible listing to a package showed one catch-all message that listed every possible reason at once and never said which of your listings tripped it:
Now you get the one reason that actually applies, naming the listing and the exact fix — for example:
The two "add child listings" conflicts (a hidden package's listing gaining its own add-ons, or picking a package's listing as an add-on elsewhere) shared that same vague message and now have their own clear ones too.
A daily add-on now explains why it needs a daily parent — it takes its date and length from the listing it's booked under, and only a daily listing has them.
The payment-provider chooser now says that switching providers keeps your other provider's saved key (it just stops using it), so entering Square doesn't look like it wiped your Stripe setup.
The free-text question note now says a free-text question can't change the price, since a price change attaches to a chosen answer and a typed answer has none.
Under the hood
The package-membership rule had been written out three separate times (the group save, the listing save, and the catalog importer). This pulls it into one shared, tested helper (
src/shared/package-membership.ts) so the rule and its wording can't drift, and removes the now-dead duplicate paths.Not in this PR (recorded in
TODO.md)The audit turned up more than a quick copy tweak could cover.
TODO.mdnow has a "Restrictions audit" section splitting the rest into message/UX fixes (flag SumUp as unavailable for your currency before you paste a key; a hint on the answer's price-modifier dropdown; moving the hardcoded group-homogeneity messages into the translatable copy; mutual-disable for the paired either/or checkboxes; naming the items when a multi-item cart shares no common date; linking the manual-adjustment page from the "refund not recorded" notice) and rule relaxations (multiple payment providers, percentage surcharges above 100%, deleting an in-use status by reassigning its holders, packages containing pay-what-you-want listings, two-level nesting, and more) — each with a starting point.Testing
🤖 Generated with Claude Code
https://claude.ai/code/session_01MD8aVv9TPPMx1rH3NgkhqN
Generated by Claude Code
Summary by CodeRabbit