@@ -13,10 +13,11 @@ interface ReviewCardProps {
1313 index : number
1414 total : number
1515 onRate : ( rating : 1 | 3 | 5 ) => void
16- isSubmitting : boolean
16+ submittingRating : 1 | 3 | 5 | null
1717}
1818
19- export function ReviewCard ( { snippet, index, total, onRate, isSubmitting } : ReviewCardProps ) {
19+ export function ReviewCard ( { snippet, index, total, onRate, submittingRating } : ReviewCardProps ) {
20+ const isSubmitting = submittingRating !== null
2021 const [ revealed , setReveal ] = useState ( false )
2122
2223 return (
@@ -120,20 +121,23 @@ export function ReviewCard({ snippet, index, total, onRate, isSubmitting }: Revi
120121 sublabel = "Start over"
121122 onClick = { ( ) => onRate ( 1 ) }
122123 disabled = { isSubmitting }
124+ isActive = { submittingRating === 1 }
123125 variant = "forgot"
124126 />
125127 < RatingButton
126128 label = "Hard"
127129 sublabel = "Got it, barely"
128130 onClick = { ( ) => onRate ( 3 ) }
129131 disabled = { isSubmitting }
132+ isActive = { submittingRating === 3 }
130133 variant = "hard"
131134 />
132135 < RatingButton
133136 label = "Easy"
134137 sublabel = "Got it!"
135138 onClick = { ( ) => onRate ( 5 ) }
136139 disabled = { isSubmitting }
140+ isActive = { submittingRating === 5 }
137141 variant = "easy"
138142 />
139143 </ div >
@@ -148,12 +152,14 @@ function RatingButton({
148152 sublabel,
149153 onClick,
150154 disabled,
155+ isActive,
151156 variant,
152157} : {
153158 label : string
154159 sublabel : string
155160 onClick : ( ) => void
156161 disabled : boolean
162+ isActive : boolean
157163 variant : "forgot" | "hard" | "easy"
158164} ) {
159165 const styles = {
@@ -170,12 +176,29 @@ function RatingButton({
170176 className = { cn (
171177 "flex flex-col items-center gap-0.5 rounded-xl border px-3 py-3.5" ,
172178 "active:scale-[0.96] transition-[transform,background-color,opacity] duration-100" ,
173- "disabled:pointer-events-none disabled:opacity-50" ,
179+ "disabled:pointer-events-none" ,
180+ isActive ? "opacity-100" : "disabled:opacity-40" ,
174181 styles [ variant ] ,
175182 ) }
176183 >
177- < span className = "text-sm font-semibold" > { label } </ span >
178- < span className = "text-[11px] opacity-70" > { sublabel } </ span >
184+ { isActive ? (
185+ < svg
186+ className = "size-4 animate-spin"
187+ viewBox = "0 0 24 24"
188+ fill = "none"
189+ aria-label = "Processing"
190+ >
191+ < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "2.5" />
192+ < path
193+ className = "opacity-75"
194+ fill = "currentColor"
195+ d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
196+ />
197+ </ svg >
198+ ) : (
199+ < span className = "text-sm font-semibold" > { label } </ span >
200+ ) }
201+ < span className = "text-[11px] opacity-70" > { isActive ? "Saving…" : sublabel } </ span >
179202 </ button >
180203 )
181204}
0 commit comments