BILLING - #124
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughCustom subscription quantity validation now enforces product-specific minimums. Selection defaults use the greater of the unit size and minimum quantity. The subscription card shows minimum-quantity errors before divisibility errors, and checkout disables invalid quantities. ChangesCustom quantity validation
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/app/(app)/settings/billing-usage/subscription/utils/subscription.utils.ts (1)
149-154: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd boundary tests for the shared validator.
validCustomQuantitynow controls update validity, checkout quantity, and package updates. Add tests fornull, below-minimum, exact-minimum, non-multiple, and valid-multiple quantities.🤖 Prompt for 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. In `@src/app/`(app)/settings/billing-usage/subscription/utils/subscription.utils.ts around lines 149 - 154, Add boundary-focused tests for validCustomQuantity covering null, below-minimum, exact-minimum, non-multiple, and valid-multiple custom quantities. Use product fixtures that exercise the minimum and required multiple, and assert null for invalid inputs while preserving the entered quantity for valid multiples.
🤖 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/app/`(app)/settings/billing-usage/subscription/components/product-subscription-card.tsx:
- Around line 241-245: Update the custom quantity validation around
customBelowMin and customNotDivisible to use the core Input/FieldWrapper error
mechanism instead of rendering a standalone paragraph. Pass the selected
validation message through fieldState.error?.message or the Input error prop,
preserving the existing minimum and divisibility messages while ensuring the
error is associated with the quantity field for screen readers.
In
`@src/app/`(app)/settings/billing-usage/subscription/hooks/use-product-selection.ts:
- Around line 73-74: Update the defaultCustomQuantity calculation so
minCustomQuantity(product) is rounded up to the next multiple of unitSize before
applying the existing lower-bound logic, ensuring the result satisfies
validCustomQuantity. Preserve the current behavior of selecting at least
unitSize and the product’s minimum quantity.
---
Nitpick comments:
In
`@src/app/`(app)/settings/billing-usage/subscription/utils/subscription.utils.ts:
- Around line 149-154: Add boundary-focused tests for validCustomQuantity
covering null, below-minimum, exact-minimum, non-multiple, and valid-multiple
custom quantities. Use product fixtures that exercise the minimum and required
multiple, and assert null for invalid inputs while preserving the entered
quantity for valid multiples.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: df2c06e4-6607-4e37-b6b0-a0c17abfc8a1
📒 Files selected for processing (3)
src/app/(app)/settings/billing-usage/subscription/components/product-subscription-card.tsxsrc/app/(app)/settings/billing-usage/subscription/hooks/use-product-selection.tssrc/app/(app)/settings/billing-usage/subscription/utils/subscription.utils.ts
| {customBelowMin ? ( | ||
| <p className="text-h6 text-ods-error"> | ||
| {`A minimum of ${minQty} ${packageUnitLabel} is required.`} | ||
| </p> | ||
| ) : customNotDivisible ? ( |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 3 'aria-(invalid|describedby)|<Input' --glob '*.{ts,tsx}' .Repository: flamingo-stack/openframe-oss-frontend
Length of output: 50393
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the relevant component section and nearby imports.
sed -n '1,280p' 'src/app/(app)/settings/billing-usage/subscription/components/product-subscription-card.tsx' | cat -n
# Inspect the core Input component to identify the documented error API if present.
printf '\n--- candidate Input component locations ---\n'
fd -i 'input' 'src' --ext ts --ext tsx | sed -n '1,80p'
printf '\n--- Input props / aria / error usage in core files ---\n'
for f in $(fd -i 'input' 'src' --ext ts --ext tsx | sed -n '1,20p'); do
echo "### $f"
rg -n -C 3 'error|aria-invalid|aria-describedby|children|forwardRef|React\.Children|useId' "$f" || true
doneRepository: flamingo-stack/openframe-oss-frontend
Length of output: 11963
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- package manifests mentioning core library package ---'
rg -n '"`@flamingo-stack/openframe-frontend-core`"|openframe-frontend-core' package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || true
printf '%s\n' '--- Input component files ---'
fd -i 'input.*\.(ts|tsx)$' 'src' --extension ts --extension tsx | sort
printf '%s\n' '--- core library imports for Input ---'
rg -n "from ['\"]`@flamingo-stack/openframe-frontend-core/components/ui`['\"]|from \['\"]`@flamingo-stack/openframe-frontend-core/components/ui`['\"]" --glob '*.{ts,tsx}' src | sed -n '1,80p'
printf '%s\n' '--- core package files ---'
fd -i '.+\.(ts|tsx|json)$' 'node_modules/@flamingo-stack/openframe-frontend-core' | sed -n '1,120p' 2>/dev/null || true
printf '%s\n' '--- Input component body ---'
input_file="$(fd -i '^input.*\.(ts|tsx)$' 'src' --extension ts --extension tsx | grep -F 'input.ts' | head -n 1 || true)"
if [ -n "$input_file" ]; then
echo "### $input_file"
cat -n "$input_file" | sed -n '1,240p'
fi
printf '%s\n' '--- docs/types for Input error props ---'
rg -n 'InputProps|interface .*Input|type .*Input|aria-invalid|aria-describedby|error:|errorMessage' src --glob '*.{ts,tsx}' | sed -n '1,200p'Repository: flamingo-stack/openframe-oss-frontend
Length of output: 44017
🌐 Web query:
@flamingo-stack/openframe-frontend-core 0.0.502 components/ui Input error aria-describedby source
💡 Result:
The @flamingo-stack/openframe-frontend-core library, version 0.0.502, provides base UI components for the Flamingo OpenFrame platform [1][2]. Within this package, the Input component (located at components/ui/input.tsx) is designed to support standard web accessibility attributes, including aria-describedby [1][3]. In the context of this library, aria-describedby is typically used to programmatically associate an input field with its error message or helper text [3][4]. When implementing an error state, the standard pattern involves: 1. Generating a unique ID for the error message container (often using a utility hook or useId). 2. Setting the aria-describedby attribute on the Input element to match the error container's ID. 3. Conditionally rendering the error text when the validation state (usually handled via react-hook-form and zod in the consuming applications) is present [2]. If you are encountering an error related to aria-describedby or its source, verify that your implementation is correctly passing the ID to the aria-describedby prop of the Input component and that the DOM element displaying the error message possesses the corresponding id. The library relies on standard HTML/ARIA practices for these components [1][2]. For the most accurate implementation details specific to version 0.0.502, you can inspect the source code directly in your node_modules/@flamingo-stack/openframe-frontend-core/components/ui/input.tsx file or refer to the openframe-oss-lib repository, which contains the design system source [1][5].
Citations:
- 1: https://registry.npmjs.org/@flamingo-stack/openframe-frontend-core
- 2: https://github.com/flamingo-stack/openframe-oss-tenant/blob/main/CLAUDE.md
- 3: flamingo-stack/openframe-oss-lib@be57045
- 4: flamingo-stack/openframe-oss-lib@3cd3b25
- 5: https://github.com/flamingo-stack/openframe-oss-lib
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "--- core Input package metadata ---"
cat node_modules/@flamingo-stack/openframe-frontend-core/package.json | jq '{version, exports}' 2>/dev/null || sed -n '1,160p' node_modules/@flamingo-stack/openframe-frontend-core/package.json
echo "--- core components/ui files ---"
fd -i 'input.*\.(ts|tsx)$' node_modules/@flamingo-stack/openframe-frontend-core --extension ts --extension tsx
echo "--- core Input source if present ---"
while IFS= read -r f; do
echo "### $f"
sed -n '1,260p' "$f"
done < <(fd -i 'input.*\.(ts|tsx)$' node_modules/@flamingo-stack/openframe-frontend-core --extension ts --extension tsx)
echo "--- Input implementations using error props in core package ---"
rg -n -C 3 'error:|errorMessage|aria-invalid|aria-describedby|id=".*error|role="alert|Text\("error|children|children:' node_modules/@flamingo-stack/openframe-frontend-core/src/components --glob '*.{ts,tsx}' | sed -n '1,240p' || true
echo "--- local error prop usage around react-hook-form Input ---"
rg -n -C 3 'fieldState|Input\(\s*\{\.\.\.field|error=\{"?\{\*fieldState|error=\{"\{\*fieldState|error={fieldState.*error|aria-describedby' --glob '*.{ts,tsx}' src/app/src/components | sed -n '1,240p'Repository: flamingo-stack/openframe-oss-frontend
Length of output: 11448
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "--- core Input source ---"
sed -n '1,340p' node_modules/@flamingo-stack/openframe-frontend-core/src/components/ui/input.tsx | cat -n
echo "--- Input story error examples ---"
sed -n '1,260p' node_modules/@flamingo-stack/openframe-frontend-core/src/stories/Input.stories.tsx | cat -n
echo "--- UI index exports ---"
sed -n '1,160p' node_modules/@flamingo-stack/openframe-frontend-core/src/components/ui/index.tsx | cat -n
echo "--- local react-hook-form Input error patterns ---"
rg -n -C 4 'fieldState\.error|error:\s*fieldState\.error|Input\(' --glob '*.{ts,tsx}' src/app src/components | sed -n '1,220p'
echo "--- focused Input with fieldState.error ---"
rg -n -C 6 'render=\{\{\s*field,\s*fieldState\s*\}.*Input|fieldState\.error|error=\{\*\*fieldState.error|error=\{\*fieldState.error' --glob '*.{ts,tsx}' src/app src/components | sed -n '1,220p'Repository: flamingo-stack/openframe-oss-frontend
Length of output: 15702
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "--- FieldWrapper source ---"
rg -l 'function FieldWrapper|const FieldWrapper|export function FieldWrapper|export const FieldWrapper' node_modules/@flamingo-stack/openframe-frontend-core/src/components/ui | xargs -r cat -n | sed -n '1,220p'
echo "--- UI index export path/source ---"
fd -i 'index.*\.(ts|tsx)$' node_modules/@flamingo-stack/openframe-frontend-core/src/components/ui --extension ts --extension tsx
for f in $(fd -i 'index.*\.(ts|tsx)$' node_modules/@flamingo-stack/openframe-frontend-core/src/components/ui --extension ts --extension tsx); do
echo "### $f"
sed -n '1,200p' "$f" | cat -n
doneRepository: flamingo-stack/openframe-oss-frontend
Length of output: 18204
Use the core Input error mechanism for the custom quantity validation.
The standalone <p> is not linked to <Input>, and this case does not use the core Input invalid/error props supported by FieldWrapper. Pass one of the status strings via fieldState.error?.message or render the chosen message through the core error prop so screen readers receive the error with the field.
🤖 Prompt for 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.
In
`@src/app/`(app)/settings/billing-usage/subscription/components/product-subscription-card.tsx
around lines 241 - 245, Update the custom quantity validation around
customBelowMin and customNotDivisible to use the core Input/FieldWrapper error
mechanism instead of rendering a standalone paragraph. Pass the selected
validation message through fieldState.error?.message or the Input error prop,
preserving the existing minimum and divisibility messages while ensuring the
error is associated with the quantity field for screen readers.
Source: Coding guidelines
| // What the Custom input pre-fills with: the smallest valid amount. | ||
| const defaultCustomQuantity = Math.max(unitSize, minCustomQuantity(product)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 'MANAGED_DEVICES|unitSize|minCustomQuantity' \
--glob '*.{ts,tsx,json,graphql}' .Repository: flamingo-stack/openframe-oss-frontend
Length of output: 34185
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== subscription.utils relevant section =="
sed -n '1,220p' src/app/\(app\)/settings/billing-usage/subscription/utils/subscription.utils.ts
echo
echo "== product selection hook relevant section =="
sed -n '1,115p' src/app/\(app\)/settings/billing-usage/subscription/hooks/use-product-selection.ts
echo
echo "== search for product defaults/catalog unitSize declarations =="
rg -n --glob '*.{ts,tsx,graphql,md,txt,yml,yaml,json}' 'AI_ASSISTANCE|MANAGED_DEVICES|unitSize|minCustomQuantity|validCustomQuantity' .
echo
echo "== behavioral probe for current formula vs validator semantics =="
python3 - <<'PY'
from typing import Optional
def min_custom_quantity(name: str) -> int:
return 10 if name == 'MANAGED_DEVICES' else 1
def valid_custom_quantity(name: str, unit_size: Optional[int], custom_quantity: Optional[int]) -> Optional[int]:
unit_size = (unit_size or 1) or 1
if custom_quantity is None:
return None
if custom_quantity < min_custom_quantity(name):
return None
if custom_quantity % unit_size != 0:
return None
return custom_quantity
def default_custom_quantity(name: str, unit_size: Optional[int] = None) -> int:
unit_size = (unit_size or 1) or 1
return max(unit_size, min_custom_quantity(name))
cases = [
('MANAGED_DEVICES', 1),
('AI_ASSISTANCE', None),
('MANAGED_DEVICES', None),
('AI_ASSISTANCE', 100_000),
# edge case for the original invariant claim
('MANAGED_DEVICES', 6),
]
for name, unit_size in cases:
default = default_custom_quantity(name, unit_size)
validator = valid_custom_quantity(name, unit_size, default)
print({'product': name, 'unitSize': unit_size, 'default': default, 'valid': validator})
PYRepository: flamingo-stack/openframe-oss-frontend
Length of output: 26630
🌐 Web query:
Openframe frontend product unitSize 100000 AI_ASSISTANCE
💡 Result:
In the context of the Flamingo Stack's OpenFrame OSS tenant, the unitSize property in the frontend billing and subscription module has been deprecated for its previous role in calculating billable units [1][2]. Previously, unitSize was used to perform unit conversions for AI and device quantities. Following a refactor to support real-token billing, the system now treats these quantities as real product counts end-to-end [1][2]. Consequently: * Scaling: All multiply/divide operations previously used to convert quantities (e.g., tier.from * unitSize) have been removed [1][2]. * Validation: unitSize is now used exclusively to validate that a custom token amount is a whole multiple of the defined unit [1][2]. * Billing Logic: Allocations and pending-plan quantities are now read directly from the backend quantity field [1]. The mention of "100000" in this context refers to a warning condition regarding the deployment of these billing changes [1]. Because the backend and frontend were updated to use real token counts rather than scaled units, there was a risk that if the backend had not yet been updated, the quantity sent to payment processors (like Stripe) would be off by a factor of 100,000 [1]. This is distinct from other technical contexts where unitSize might represent physical product dimensions or packaging quantities in retail scrapers [3][4][5][6].
Citations:
- 1: feat(frontend): real-token billing usage + invoices history openframe-oss-tenant#1953
- 2: flamingo-stack/openframe-oss-tenant@3d6f1e0
- 3: https://apis.io/schemas/united-natural-foods/unfi-supplier-product/
- 4: https://apify.com/illehius/asda-scraper/api/javascript
- 5: https://apify.com/illehius/tesco-scraper/api/javascript
- 6: https://apify.com/blackfalcondata/rema1000-scraper/api/javascript
🌐 Web query:
site:github.com/flamingo-stack/openframe-oss-tenant unitSize 100000 AI_ASSISTANCE
💡 Result:
In the context of the Flamingo Stack open-source project (specifically openframe-oss-tenant), unitSize was a billing parameter previously used to handle AI/device quantity scaling [1][2]. Historically, this system used unitSize to manage billable units—where a single unit might represent a package of items (e.g., a batch of tokens or conversations). Recent refactoring has moved the system toward using real product counts (such as raw token amounts) directly [1]. As part of this transition, unitSize was relegated to a validation role, ensuring that user-provided custom token amounts are whole multiples of the defined unit size [1][2]. If you encounter unitSize 100000 in legacy configurations or code, it refers to a legacy scaling factor where 1 unit represented 100,000 of the underlying metric (likely AI tokens) [1][2]. The backend logic has been updated to treat these metrics as direct counts, and multiplying or dividing by this unitSize for quantity calculations is no longer the standard architectural approach [1].
Citations:
- 1: feat(frontend): real-token billing usage + invoices history openframe-oss-tenant#1953
- 2: flamingo-stack/openframe-oss-tenant@3d6f1e0
🌐 Web query:
site:github.com/flamingo-stack/openframe-oss Tenant unitSize 100000 AI_ASSISTANCE
💡 Result:
The repository appears to be flamingo-stack/openframe-oss-tenant, not openframe-oss. I couldn’t find an indexed match for all three terms (Tenant, unitSize: 100000, and AI_ASSISTANCE). The relevant OpenFrame tenant repository is referenced in Flamingo’s documentation. [1]
Citations:
🌐 Web query:
github "unitSize" "AI_ASSISTANCE" "100000"
💡 Result:
There is no widely recognized technical parameter, library feature, or standard configuration named "unitSize" associated with the specific value "100000" in the context of generic AI assistant software [1][2][3][4]. Research indicates that "AI_ASSISTANCE" and "ai_assistant" are common names for various software projects, including: - OrlandoLuque/ai_assistant: A Rust-based library for LLM integration that uses various "Known Model Context Sizes" (e.g., 128K tokens for many models) [1][2], but does not contain a "unitSize" parameter set to 100,000. - Unity AI Assistant: A generative AI tool integrated into the Unity Editor [4][5]. - RapidKit AI Assistant Module: A provider-agnostic Python runtime module [6]. It is possible that "unitSize: 100000" refers to a custom configuration variable, a specific buffer size, or an indexing threshold within a private or specialized codebase not indexed in public technical documentation [7][8]. If this relates to a specific project, it is likely a user-defined constant for memory allocation, token window processing, or data chunking [7][3].
Citations:
- 1: https://github.com/OrlandoLuque/ai_assistant/tree/v0.2.27
- 2: https://github.com/OrlandoLuque/ai_assistant/tree/b7218fc9ce3f06b7546c12e5f1bdf58114dd8c1d
- 3: https://ai-assistant.runawaybrains.com/developer_guide.html
- 4: https://docs.unity3d.com/Manual/com.unity.ai.assistant.html
- 5: https://docs.unity3d.com/Packages/com.unity.ai.assistant@2.8/manual/index.html
- 6: https://github.com/chistiq/rapidkit-core/tree/main/src/modules/free/ai/ai_assistant
- 7: https://github.com/microsoft/vscode-copilot-chat/blob/4995bb86/src/platform/workspaceChunkSearch/node/codeSearch/codeSearchChunkSearch.ts
- 8: https://cocalc.com/github/microsoft/vscode/blob/main/extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/codeSearchChunkSearch.ts
Make the custom default satisfy validCustomQuantity.
Math.max(unitSize, minCustomQuantity(product)) can pre-fill an invalid custom quantity, for example 10 when MANAGED_DEVICES.unitSize is less than 10 but not a divisor of 10. Round minCustomQuantity(product) up to the next multiple of unitSize before using it as the Custom Amount default.
🤖 Prompt for 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.
In
`@src/app/`(app)/settings/billing-usage/subscription/hooks/use-product-selection.ts
around lines 73 - 74, Update the defaultCustomQuantity calculation so
minCustomQuantity(product) is rounded up to the next multiple of unitSize before
applying the existing lower-bound logic, ensuring the result satisfies
validCustomQuantity. Preserve the current behavior of selecting at least
unitSize and the product’s minimum quantity.
…e in HubSpot sync
https://claude.ai/code/session_01CRtdbVqb77ef3JY398kRhB
Summary by CodeRabbit