Bump SDK to 0.16#83
Conversation
* Support Gift Cards on checkout * Improve Order Placed page
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughUnified coupon handling: SDK deps bumped; checkout data-layer now exposes Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client (browser)
participant CheckoutPage as Checkout Page UI
participant DataLayer as Checkout Data Layer
participant SpreeAPI as Spree SDK / API
Client->>CheckoutPage: submit code
CheckoutPage->>DataLayer: applyCode(cartId, code)
DataLayer->>SpreeAPI: applyDiscountCode(code)
alt discount success
SpreeAPI-->>DataLayer: { success, cart }
DataLayer-->>CheckoutPage: { success, type: "discount", cart }
else discount not found (422/404)
SpreeAPI-->>DataLayer: error(422)
DataLayer->>SpreeAPI: applyGiftCard(code)
alt gift card success
SpreeAPI-->>DataLayer: { success, cart }
DataLayer-->>CheckoutPage: { success, type: "gift_card", cart }
else both fail
SpreeAPI-->>DataLayer: error
DataLayer-->>CheckoutPage: { success: false, error }
end
else discount error (non-422)
SpreeAPI-->>DataLayer: error
DataLayer-->>CheckoutPage: { success: false, error }
end
CheckoutPage-->>Client: update UI with new cart state / error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/checkout/CouponCode.tsx (1)
37-52:⚠️ Potential issue | 🟠 MajorAsync handlers can leave UI stuck on failures.
If
onApply/onRemoveDiscount/onRemoveGiftCardthrows, loading state is never reset.🛠️ Proposed hardening with
try/catch/finally- const handleApply = async (e: React.FormEvent) => { + const handleApply = async (e: React.FormEvent): Promise<void> => { e.preventDefault(); - if (!code.trim()) return; + const trimmedCode = code.trim(); + if (!trimmedCode) return; setApplying(true); setError(null); - const result = await onApply(code.trim()); - if (result.success) { - setCode(""); - } else { - setError(result.error || "Invalid code"); + try { + const result = await onApply(trimmedCode); + if (result.success) { + setCode(""); + } else { + setError(result.error || "Invalid code"); + } + } catch { + setError("Failed to apply code"); + } finally { + setApplying(false); } - - setApplying(false); }; - const handleRemoveDiscount = async (discountCode: string) => { + const handleRemoveDiscount = async (discountCode: string): Promise<void> => { setRemoving(discountCode); setError(null); - const result = await onRemoveDiscount(discountCode); - if (!result.success) { - setError(result.error || "Failed to remove discount code"); + try { + const result = await onRemoveDiscount(discountCode); + if (!result.success) { + setError(result.error || "Failed to remove discount code"); + } + } catch { + setError("Failed to remove discount code"); + } finally { + setRemoving(null); } - - setRemoving(null); }; - const handleRemoveGiftCard = async () => { + const handleRemoveGiftCard = async (): Promise<void> => { if (!appliedGiftCard) return; setRemoving(appliedGiftCard.id); setError(null); - const result = await onRemoveGiftCard(appliedGiftCard.id); - if (!result.success) { - setError(result.error || "Failed to remove gift card"); + try { + const result = await onRemoveGiftCard(appliedGiftCard.id); + if (!result.success) { + setError(result.error || "Failed to remove gift card"); + } + } catch { + setError("Failed to remove gift card"); + } finally { + setRemoving(null); } - - setRemoving(null); };Also applies to: 54-64, 66-78
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/checkout/CouponCode.tsx` around lines 37 - 52, The async handlers (handleApply and the similar handlers for removal: handleRemoveDiscount and handleRemoveGiftCard) can throw and leave the UI stuck; wrap the await onApply/onRemoveDiscount/onRemoveGiftCard calls in try/catch/finally blocks so any thrown exception is caught, setError is updated on failure (using the caught error message or a default), and the loading state (setApplying / setLoading / setRemoving as used in each handler) is always reset in the finally block; update each handler to use try { const result = await ...; handle success path (clear code / update state) } catch (err) { setError(err?.message || "Operation failed") } finally { reset the corresponding loading flag }.
🧹 Nitpick comments (2)
src/lib/data/checkout.ts (1)
82-120: Add explicit return types to the new checkout actions.
applyCodenow returns a non-trivial discriminated union, and the two remove actions are part of the same public server-action surface. Please pin these return types explicitly so downstream handlers do not widen silently as this flow evolves.As per coding guidelines, "Use strict TypeScript type checking. Always define explicit return types for functions, use 'satisfies' for type checking object literals, and avoid 'any' (use 'unknown' instead)."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/data/checkout.ts` around lines 82 - 120, Add explicit return type annotations: declare a discriminated union type (e.g. CheckoutApplyResult = { success: true; cart: Cart; type: "discount" | "gift_card" } | { success: false; error: string }) and annotate applyCode as async function applyCode(cartId: string, code: string): Promise<CheckoutApplyResult>. Also add explicit return types for removeDiscountCode and removeGiftCard (e.g. Promise<ActionResult<{ cart: Cart }>> or the project’s existing action result type) and ensure returned object literals use satisfies for shape checking and avoid any by using unknown when needed; update the signatures for removeDiscountCode and removeGiftCard to include those explicit Promise return types and keep references to _applyDiscountCode, _applyGiftCard, _removeDiscountCode, and _removeGiftCard unchanged.src/components/checkout/CouponCode.tsx (1)
20-25: Add explicit return type to the component export.For strict TS consistency, type the component return explicitly.
✍️ Suggested typing
export function CouponCode({ cart, onApply, onRemoveDiscount, onRemoveGiftCard, -}: CouponCodeProps) { +}: CouponCodeProps): JSX.Element {As per coding guidelines, "Use strict TypeScript type checking. Always define explicit return types for functions."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/checkout/CouponCode.tsx` around lines 20 - 25, The component export CouponCode lacks an explicit return type; update its signature to include a strict React return type (e.g., JSX.Element or React.ReactElement) so it reads like CouponCode(...): JSX.Element, and add an import for the React types if not already present; keep CouponCodeProps as-is and ensure the implementation still returns a valid JSX element.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/`[country]/[locale]/(checkout)/order-placed/[id]/page.tsx:
- Around line 278-287: Replace the use of the order-level flag when rendering
each payment row and instead derive the label from the payment object: check
payment.source_type on the payment (e.g., payment.source_type ===
"Spree::GiftCard" ? "Gift Card" : "Store Credit") where the current code uses
order.gift_card, leaving payment.display_amount and other fields as-is; ensure
the conditional that currently branches on payment.source_type ===
"store_credit" && payment.source still renders but the displayed label comes
from payment.source_type to correctly distinguish "Spree::GiftCard" vs
"Spree::StoreCredit".
In `@src/components/checkout/CouponCode.tsx`:
- Line 80: The visibility check for the discount input uses OR and hides the
field when either coupons or a gift card exist; change the boolean logic in the
hasAppliedCode declaration to use AND so the input only hides when both
couponPromotions and appliedGiftCard are present. Locate the hasAppliedCode
constant in CouponCode.tsx (references: couponPromotions, appliedGiftCard,
hasAppliedCode) and update the expression accordingly, then run UI to verify
both types can be applied simultaneously.
In `@src/lib/data/checkout.ts`:
- Around line 87-103: The applyCode function needs an explicit return type and
must only fall back to _applyGiftCard when the discount failure is a SpreeError
indicating an invalid/not-found discount; change the signature of applyCode to
include the proper return type (the union shape currently returned: success true
with cart and type, or success false with error), and in the catch of
_applyDiscountCode only call _applyGiftCard when discountError instanceof
SpreeError and discountError.code matches the invalid/not-found codes you use
(e.g., "discount_not_found"/"invalid_discount"); otherwise immediately return
the original discountError message; update or add a unit test to cover the
SpreeError code path so the gift-card retry happens only for that specific error
code.
---
Outside diff comments:
In `@src/components/checkout/CouponCode.tsx`:
- Around line 37-52: The async handlers (handleApply and the similar handlers
for removal: handleRemoveDiscount and handleRemoveGiftCard) can throw and leave
the UI stuck; wrap the await onApply/onRemoveDiscount/onRemoveGiftCard calls in
try/catch/finally blocks so any thrown exception is caught, setError is updated
on failure (using the caught error message or a default), and the loading state
(setApplying / setLoading / setRemoving as used in each handler) is always reset
in the finally block; update each handler to use try { const result = await ...;
handle success path (clear code / update state) } catch (err) {
setError(err?.message || "Operation failed") } finally { reset the corresponding
loading flag }.
---
Nitpick comments:
In `@src/components/checkout/CouponCode.tsx`:
- Around line 20-25: The component export CouponCode lacks an explicit return
type; update its signature to include a strict React return type (e.g.,
JSX.Element or React.ReactElement) so it reads like CouponCode(...):
JSX.Element, and add an import for the React types if not already present; keep
CouponCodeProps as-is and ensure the implementation still returns a valid JSX
element.
In `@src/lib/data/checkout.ts`:
- Around line 82-120: Add explicit return type annotations: declare a
discriminated union type (e.g. CheckoutApplyResult = { success: true; cart:
Cart; type: "discount" | "gift_card" } | { success: false; error: string }) and
annotate applyCode as async function applyCode(cartId: string, code: string):
Promise<CheckoutApplyResult>. Also add explicit return types for
removeDiscountCode and removeGiftCard (e.g. Promise<ActionResult<{ cart: Cart
}>> or the project’s existing action result type) and ensure returned object
literals use satisfies for shape checking and avoid any by using unknown when
needed; update the signatures for removeDiscountCode and removeGiftCard to
include those explicit Promise return types and keep references to
_applyDiscountCode, _applyGiftCard, _removeDiscountCode, and _removeGiftCard
unchanged.
🪄 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: CHILL
Plan: Pro
Run ID: 5dae26e7-d530-4019-ad3f-aae16f4944c5
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
package.jsonsrc/app/[country]/[locale]/(checkout)/checkout/[id]/page.tsxsrc/app/[country]/[locale]/(checkout)/order-placed/[id]/page.tsxsrc/app/[country]/[locale]/(storefront)/cart/page.tsxsrc/components/account/OrderDetail.tsxsrc/components/checkout/CouponCode.tsxsrc/components/checkout/Summary.tsxsrc/lib/data/__tests__/checkout.test.tssrc/lib/data/checkout.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/lib/data/checkout.ts`:
- Around line 101-108: The fallback catch block currently returns the stale
discountError message; change it to prefer the gift-card failure details
instead: when catching giftCardError in the block that calls _applyGiftCard, set
error to giftCardError.message if giftCardError is an Error, otherwise fall back
to "Invalid code" (or normalize both to "Invalid code" if you want uniform UX).
Update the return to use that computed error (referencing _applyGiftCard,
giftCardError, and discountError so you only replace the discountError usage in
this catch).
🪄 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: CHILL
Plan: Pro
Run ID: 13ac3f4a-f847-4f41-bd7b-09062bff3a62
📒 Files selected for processing (3)
src/components/checkout/CouponCode.tsxsrc/lib/data/__tests__/checkout.test.tssrc/lib/data/checkout.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/checkout/CouponCode.tsx
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/order/AddressBlock.tsx`:
- Around line 14-16: The city/state/postal line currently interpolates
address.city, address.state_text and address.postal_code with fixed separators
which produces awkward output when fields are empty; update the rendering in
AddressBlock (the component using address.city, address.state_text,
address.postal_code) to build the line by collecting those three pieces into an
array, filtering out empty/undefined values (e.g., filter(Boolean)), and joining
with the proper separators (e.g., ", " between city and the rest or " " between
state and postal) so only existing parts are shown and no stray commas/undefined
appear.
In `@src/components/order/OrderTotals.tsx`:
- Around line 46-61: The current JSX uses a chained ternary so the store credit
branch is skipped whenever gift card is truthy; update the OrderTotals component
to render the gift-card and store-credit deduction blocks independently by
replacing the ternary with two separate conditional renders (e.g., render the
gift card block when order.gift_card && Number.parseFloat(order.gift_card_total)
> 0, and separately render the store credit block when order.store_credit_total
&& Number.parseFloat(order.store_credit_total) > 0), keeping the existing markup
and display fields (order.display_gift_card_total,
order.display_store_credit_total) so both deductions can appear together in the
breakdown.
🪄 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: CHILL
Plan: Pro
Run ID: dc1ccd64-6165-43a9-8106-f8d72bc3a1ee
📒 Files selected for processing (6)
src/app/[country]/[locale]/(checkout)/order-placed/[id]/page.tsxsrc/components/account/OrderDetail.tsxsrc/components/order/AddressBlock.tsxsrc/components/order/OrderTotals.tsxsrc/components/order/PaymentInfo.tsxsrc/lib/data/__tests__/checkout.test.ts
Summary by CodeRabbit
New Features
Improvements
Tests
Chores