shadcn.io is not affiliated with official shadcn/ui
Incentive Program Reviews Block for React Aria
Thank-you points for a pet-supplies shop: a balance, a tier with a Progress, two rewards that confirm in an AlertDialog and a ledger table, with the policy that points never depend on the rating.
Installation
Overview
A thank-you points account for React with React Aria, for Grangeline, a fictional pet-supplies shop. A divider splits the section. At the start, a compact header and four cells on shared hairlines: the points balance with what was earned and spent, the tier (Scout, Tracker or Ranger) with a Progress to the next one and how many points are still needed, and two rewards (a free sample bag and $5 off), each with its cost and a button that opens an AlertDialog to confirm. At the end, one line of policy, "Points never depend on your rating", over the ledger: a table of the latest six entries (a review written, a photo added, a reply read, a reward redeemed) with dates and signed points. Redeeming a reward takes its cost off the balance and puts a row at the top of the ledger, on this page only. Every figure is worked out from the typed ledger: the balance, the earned total, the tier and the points still needed. On a phone the ledger drops its date column and shows the day under each activity. It's built from Progress, AlertDialog, Button and Guides, with a native table.
FAQ
Why does the page say points never depend on the rating?
Because paying for good ratings, or only for them, is the kind of incentive that makes reviews untrustworthy and, in many places, is against advertising and consumer rules. Every entry in the ledger earns the same whatever stars the review gave, the sentence says a one-star review earns what a five-star one does, and the reward rules in the file take no rating. Keep that true in your own program.
How do I use my own ledger?
Edit LEDGER (newest first; each entry has an activity, an ISO date and signed points), REWARDS (a cost and a short description each) and TIERS (where each starts). The balance is the earned points minus the spent ones, the tier is the last whose start has been passed, and the Progress is the share of the way to the next tier, all computed when the module loads. Only the latest six entries show, so a new row never changes the block's height; the line under the table says how many there are.
What does Redeem actually do?
It opens a confirmation that states the cost and what will remain. Confirming takes the cost off the balance and adds a "Redeemed" row to the ledger, locally: nothing is issued and a reload starts afresh. A reward you can't afford still takes focus, but pressing it doesn't open anything, and the line above it says how many more points it needs, so keyboard users can always reach it and learn why.
The trigger holds the Button and the dialog, and takes isOpen and onOpenChange.
Do redeemed points lower the tier?
No. The tier counts points earned, not the balance, so spending never sends a customer back down; the cell shows the earned and spent totals so both numbers are visible.
Is the ledger an accessible table?
Yes: a native table with a caption that says how many of the entries it shows, column headers with scope, and a scroll region that takes keyboard focus when the table is wider than its box. Amounts carry a plus or a true minus sign, so they read the same without colour.