useCoupon
Applies or removes a discount coupon on the shopper's cart through the Salla SDK, with loading and error state.
import { useCoupon, UseCouponResult } from '@salla.sa/twilight-theme-engine/hooks/useCoupon';In plain words
Lets a shopper type a discount code. apply('WELCOME10') asks Salla to add it to the cart and resolves true or false. remove() takes it off.
While a request is on its way loading is true, and when one fails error holds the message to show. value is the code this component applied.
Signature
function useCoupon(): UseCouponResult
type UseCouponResult = UseApply<string>;
// {
// value: string | null;
// apply: (code: string) => Promise<boolean>;
// remove: () => Promise<boolean>;
// loading: boolean; error: string | null;
// }Try it live
value: null · loading: false · error: null
import { useState } from 'react';
import { useCoupon } from '@salla.sa/twilight-theme-engine/hooks/useCoupon';
export function CouponBox() {
const { apply, loading, error } = useCoupon();
const [code, setCode] = useState('WELCOME10');
return (
<form
onSubmit={async (event) => {
event.preventDefault();
if (await apply(code)) setCode('');
}}
>
<input value={code} onChange={(event) => setCode(event.target.value)} />
<button disabled={loading}>Apply</button>
{error && <p role="alert">{error}</p>}
</form>
);
}
Example
import { useState } from 'react';
import { useCoupon } from '@salla.sa/twilight-theme-engine/hooks/useCoupon';
export function CouponForm() {
const { apply, loading, error } = useCoupon();
const [code, setCode] = useState('');
return (
<form
onSubmit={async (event) => {
event.preventDefault();
if (await apply(code)) setCode('');
}}
>
<input value={code} onChange={(event) => setCode(event.target.value)} placeholder="Coupon" />
<button type="submit" disabled={loading}>
{loading ? 'Applying…' : 'Apply'}
</button>
{error && <p role="alert">{error}</p>}
</form>
);
}
How it behaves
apply(code)trims the code and callsSalla.cart.addCoupon(code);remove()callsSalla.cart.deleteCoupon(). An empty or whitespace-only code throws "Please enter a coupon code" before any request, which shows up aserror.It is built on two
useAsyncFncalls.loadingis true while either runs, anderroris the message of the apply error, else the remove error.State belongs to each component that calls the hook; two coupon boxes do not share it.
Salla's SDK creates a cart for a guest who has none when a coupon is applied.
The engine's
CartSummaryuses it for its coupon field.
Gotchas
valuestarts asnulland never reads the coupon already on the cart, and it isnullagain after a successfulremove().value ?? cart.coupon(the engine'sCartSummarypattern) therefore shows the removed coupon again until the cart data refreshes.applyandremoveresolvetrueunless what was thrown is anError. Withoutwindow.Salla(for example during a test), the optional call does nothing and they still resolvetrue, withvalueset.The hook does not refresh cart totals. Update the cart from the SDK cart events or your cart query after it resolves.
Related
Source and docs
- Engine source:
packages/theme-engine/src/hooks/useCoupon.ts