diff --git a/apps/scandic-web/docs/rewards.md b/apps/scandic-web/docs/rewards.md new file mode 100644 index 000000000..fef316e99 --- /dev/null +++ b/apps/scandic-web/docs/rewards.md @@ -0,0 +1,113 @@ +# Rewards System + +This doc provides a comprehensive guide to the rewards system for developers maintaining the codebase. + +## Overview + +The rewards system manages loyalty benefits for Scandic Hotels members. It combines data from two sources: + +1. **Scandic Profile API** - Provides reward availability, states, and coupon codes +2. **Contentstack CMS** - Provides reward content (labels, descriptions, redeem instructions) + +Rewards are tied to **membership levels** (L1-L7, called "Friends") and come in different **types** (Tier, Surprise, Campaign, Member-voucher). + +```` + +### Data Merging Process + +Rewards are matched between API and CMS using the `reward_id` field: + +```typescript +// From query.ts - merging API and CMS data +const rewards: BaseReward[] = cmsRewards.map((cmsReward) => { + const apiReward = redeemableRewards.find( + ({ rewardId }) => rewardId === cmsReward.reward_id + )! + return { + ...apiReward, // API data: status, coupon codes, redeem location + ...cmsReward, // CMS data: label, description, redeem_description + } +}) +```` + +## Reward Types + +### 1. Tier Rewards (`rewardType: "Tier"`) + +Permanent benefits tied to membership level. These are always available once a member reaches the required tier. + +**Characteristics:** + +- Linked to `rewardTierLevel` (e.g., "L1", "L2") +- No coupon codes required for most +- Examples: 10% food discount, early check-in, late checkout + +**Redeem behavior:** + +- `On-site`: Show membership number at hotel +- `Non-redeemable`: Display-only benefits (e.g., earn rate bonuses) + +### 2. Surprise Rewards (`rewardType: "Surprise"`) + +Special rewards that appear as wrapped gifts and need to be "unwrapped" before use. + +**Characteristics:** + +- Part of `coupons` array in API response +- Have `unwrapped: boolean` flag on each coupon +- Must call `unwrap` mutation before becoming redeemable +- After unwrapping, appear in regular rewards list + +**Flow:** + +1. User sees surprise modal with wrapped gift +2. User clicks to reveal/unwrap +3. Frontend calls `rewards.unwrap` mutation +4. Surprise moves to current rewards + +### 3. Campaign Rewards (`rewardType: "Campaign"`) + +Promotional rewards with promo codes for online use. + +**Characteristics:** + +- Part of `coupons` array +- Have `couponCode` for redemption +- Typically redeemed online +- May have expiration dates + +**Redeem behavior:** + +- Display promo code with copy-to-clipboard functionality + +### 4. Member Voucher (`rewardType: "Member-voucher"`) + +Voucher-based rewards similar to campaigns. + +**Characteristics:** + +- Part of `coupons` array +- Have coupon codes +- Similar flow to Campaign rewards + +--- + +## Coupon States & Redemption + +### Coupon States + +| State | Description | Redeemable | +| ---------- | ---------------------------------------------- | ---------- | +| `claimed` | Coupon has been claimed by user | Yes | +| `viewed` | Coupon has been viewed (schema only, not used) | Yes | +| `redeemed` | Coupon has been used | No | + +**Note:** Only `redeemed` state is actively filtered out in business logic. Both `claimed` and `viewed` are treated as redeemable. + +### Redeem Locations + +| Location | Description | UI Behavior | +| ---------------- | --------------------------------- | ----------------------------- | +| `On-site` | Redeem at hotel (show to staff) | Shows membership number badge | +| `Online` | Redeem digitally with promo code | Shows copy-to-clipboard | +| `Non-redeemable` | Display-only (automatic benefits) | No redeem button, info only |