11"use client" ;
22
3+ import { CheckIcon , InfoIcon } from "lucide-react" ;
34import { useQueryState } from "nuqs" ;
45import { useMemo , useState , useTransition } from "react" ;
56import { toast } from "sonner" ;
67import { getChainInfraCheckoutURL } from "@/actions/billing" ;
78import { reportChainInfraRpcOmissionAgreed } from "@/analytics/report" ;
9+ import { Alert , AlertTitle } from "@/components/ui/alert" ;
810import { Badge } from "@/components/ui/badge" ;
911import { Button } from "@/components/ui/button" ;
1012import {
@@ -115,11 +117,11 @@ export function DeployInfrastructureForm(props: {
115117
116118 const bundleHint = useMemo ( ( ) => {
117119 if ( selectedCount === 1 ) {
118- return "Add one more add-on to unlock a 10% bundle discount. " ;
120+ return "Add one more add-on to unlock a 10% bundle discount" ;
119121 } else if ( selectedCount === 2 ) {
120- return "Add another add-on to increase your bundle discount to 15%. " ;
122+ return "Add another add-on to increase your bundle discount to 15%" ;
121123 } else if ( selectedCount >= 3 ) {
122- return "🎉 Congrats! You unlocked the maximum 15% bundle discount. " ;
124+ return "Congrats! You unlocked the maximum 15% bundle discount" ;
123125 }
124126 return null ;
125127 } , [ selectedCount ] ) ;
@@ -234,8 +236,8 @@ export function DeployInfrastructureForm(props: {
234236 return (
235237 < div className = "flex flex-col gap-8 lg:flex-row" >
236238 { /* Left column: service selection + frequency */ }
237- < div className = "flex flex-col gap-4 " >
238- < h3 className = "text-lg font-semibold" > Select Services</ h3 >
239+ < div className = "flex flex-col gap-3 " >
240+ < h3 className = "text-xl font-semibold tracking-tight" > Services</ h3 >
239241
240242 { /* RPC (now optional) */ }
241243 < div className = "flex flex-col gap-2 mb-6" >
@@ -258,13 +260,11 @@ export function DeployInfrastructureForm(props: {
258260
259261 { /* Optional add-ons */ }
260262 < div className = "flex flex-col gap-2" >
261- < div className = "flex items-center justify-between" >
262- < p className = "text-muted-foreground text-sm" > Add-ons</ p >
263- { bundleHint && (
264- < p className = "text-xs font-medium text-primary" > { bundleHint } </ p >
265- ) }
263+ < div className = "flex flex-col lg:flex-row lg:items-center lg:justify-between" >
264+ < h3 className = "text-xl font-semibold tracking-tight" > Add-ons</ h3 >
266265 </ div >
267- < div className = "grid gap-4 sm:grid-cols-2" >
266+
267+ < div className = "space-y-4" >
268268 { /* Insight */ }
269269 < ServiceCard
270270 description = { SERVICE_CONFIG . insight . description }
@@ -304,14 +304,21 @@ export function DeployInfrastructureForm(props: {
304304 price = { pricePerService . accountAbstraction }
305305 selected = { includeAA }
306306 />
307+
308+ { bundleHint && (
309+ < Alert variant = "default" className = "relative overflow-hidden" >
310+ < InfoIcon className = "size-5" />
311+ < AlertTitle > { bundleHint } </ AlertTitle >
312+ </ Alert >
313+ ) }
307314 </ div >
308315 </ div >
309316 </ div >
310317
311318 { /* Right column: order summary */ }
312- < div className = "w-full lg:max-w-sm border rounded-md p-6 bg-muted/30 h-fit" >
313- < h3 className = "font-medium mb-4" > Order Summary</ h3 >
314- < div className = "space-y-2 text-sm" >
319+ < div className = "w-full lg:max-w-sm border rounded-xl p-4 bg-card h-fit" >
320+ < h3 className = "font-semibold mb-4 text-lg " > Order Summary</ h3 >
321+ < div className = "space-y-3 text-sm" >
315322 { selectedOrder . map ( ( key ) => (
316323 < div className = "flex justify-between" key = { key } >
317324 < span > { SERVICE_CONFIG [ key ] . label } </ span >
@@ -329,15 +336,16 @@ export function DeployInfrastructureForm(props: {
329336 </ div >
330337 ) ) }
331338
332- < div className = "flex justify-between pt-2 border-t mt-2 " >
339+ < div className = "flex justify-between pt-3 border-t mt-3 " >
333340 < span > Subtotal</ span >
334341 < span >
335342 { formatUSD ( subtotal ) }
336343 { periodLabel }
337344 </ span >
338345 </ div >
346+
339347 { bundleDiscount > 0 && (
340- < div className = "flex justify-between text-green-600" >
348+ < div className = "flex justify-between text-green-600 font-medium " >
341349 < span >
342350 Bundle Discount (
343351 { Object . values ( selectedServices ) . filter ( Boolean ) . length === 2
@@ -485,50 +493,52 @@ function ServiceCard(props: {
485493 icon,
486494 onToggle,
487495 } = props ;
496+
497+ const IconComp = getIcon ( icon ) ;
488498 return (
489499 < button
490500 className = { cn (
491- "flex flex-col items-start gap-3 rounded-lg p-4 text-left transition-colors border" ,
492- disabled
493- ? "border-primary bg-primary/10"
494- : selected
495- ? "border-primary bg-primary/10 hover:bg-primary/10 hover:border-primary/50"
496- : "hover:border-primary/50 hover:bg-muted/40" ,
501+ "flex bg-card flex-col items-start rounded-xl p-4 text-left transition-colors border relative" ,
502+ disabled && "opacity-50" ,
497503 ) }
498504 disabled = { disabled }
499505 onClick = { ( ) => ! disabled && onToggle ( ) }
500506 type = "button"
501507 >
502- < div className = "flex items-center justify-between w-full" >
503- < h4 className = "font-semibold text-lg leading-none flex gap-2 items-center" >
504- { ( ( ) => {
505- const IconComp = getIcon ( icon ) ;
506- return < IconComp className = "size-4" /> ;
507- } ) ( ) }
508- { label }
509- { required && < Badge variant = "outline" > Always Included</ Badge > }
510- </ h4 >
511- { ! disabled && (
512- < span
513- className = { cn (
514- "size-4 rounded-full border flex items-center justify-center transition-colors" ,
515- selected ? "bg-primary border-primary" : "" ,
516- ) }
517- >
518- { selected && < span className = "size-2 bg-card rounded-full" /> }
519- </ span >
520- ) }
508+ < div className = "flex mb-4" >
509+ < div className = "rounded-full p-2 bg-card border" >
510+ < IconComp className = "size-4 text-muted-foreground" />
511+ </ div >
521512 </ div >
513+
514+ { ! disabled && (
515+ < span
516+ className = { cn (
517+ "absolute top-4 right-4 size-6 rounded-full border-2 border-active-border flex items-center justify-center transition-colors" ,
518+ selected && "border-foreground bg-foreground" ,
519+ ) }
520+ >
521+ { selected && (
522+ < CheckIcon className = "size-4 text-inverted-foreground" />
523+ ) }
524+ </ span >
525+ ) }
526+
527+ < h4 className = "font-semibold text-lg mb-1 flex gap-2 items-center" >
528+ { label }
529+ { required && < Badge variant = "outline" > Always Included</ Badge > }
530+ </ h4 >
522531 < p className = "text-muted-foreground text-sm min-h-[48px]" >
523532 { description }
524533 </ p >
525- < p className = "mt-auto font-medium flex items-center gap-2" >
534+
535+ < p className = "mt-auto pt-3 font-medium flex items-center gap-2" >
526536 { originalPrice && (
527537 < span className = "text-muted-foreground line-through text-xs" >
528538 { formatUSD ( originalPrice ) }
529539 </ span >
530540 ) }
531- < span >
541+ < span className = "font-medium" >
532542 { formatUSD ( price ) }
533543 { periodLabel }
534544 </ span >
0 commit comments