@@ -16,7 +16,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
1616import { useMutation , useQuery } from "@tanstack/react-query" ;
1717import { format , fromUnixTime } from "date-fns" ;
1818import { TagIcon } from "lucide-react" ;
19- import { useState } from "react" ;
19+ import { useSearchParams } from "next/navigation" ;
20+ import { Suspense , useEffect , useRef , useState } from "react" ;
2021import { useForm } from "react-hook-form" ;
2122import { toast } from "sonner" ;
2223import { z } from "zod" ;
@@ -37,9 +38,13 @@ function ApplyCouponCard(props: {
3738 teamId : string | undefined ;
3839 onCouponApplied : ( data : ActiveCouponResponse ) => void ;
3940} ) {
41+ const searchParams = useSearchParams ( ) ;
42+ const couponCode = searchParams ?. get ( "coupon" ) ;
4043 return (
4144 < ApplyCouponCardUI
4245 onCouponApplied = { props . onCouponApplied }
46+ prefillPromoCode = { couponCode || undefined }
47+ scrollIntoView = { ! ! couponCode }
4348 submit = { async ( promoCode : string ) => {
4449 const res = await fetch ( "/api/server-proxy/api/v1/coupons/redeem" , {
4550 method : "POST" ,
@@ -79,14 +84,30 @@ export function ApplyCouponCardUI(props: {
7984 data : null | ActiveCouponResponse ;
8085 } > ;
8186 onCouponApplied : ( ( data : ActiveCouponResponse ) => void ) | undefined ;
87+ prefillPromoCode ?: string ;
88+ scrollIntoView ?: boolean ;
8289} ) {
90+ const containerRef = useRef < HTMLFormElement | null > ( null ) ;
8391 const form = useForm < z . infer < typeof couponFormSchema > > ( {
8492 resolver : zodResolver ( couponFormSchema ) ,
8593 defaultValues : {
86- promoCode : "" ,
94+ promoCode : props . prefillPromoCode ,
8795 } ,
8896 } ) ;
8997
98+ const scrolled = useRef ( false ) ;
99+ // eslint-disable-next-line no-restricted-syntax
100+ useEffect ( ( ) => {
101+ if ( props . scrollIntoView && ! scrolled . current ) {
102+ const el = containerRef . current ;
103+ if ( el ) {
104+ el . scrollIntoView ( { behavior : "smooth" , block : "start" } ) ;
105+ el . querySelector ( "input" ) ?. focus ( ) ;
106+ scrolled . current = true ;
107+ }
108+ }
109+ } , [ props . scrollIntoView ] ) ;
110+
90111 const applyCoupon = useMutation ( {
91112 mutationFn : ( promoCode : string ) => props . submit ( promoCode ) ,
92113 } ) ;
@@ -133,7 +154,7 @@ export function ApplyCouponCardUI(props: {
133154
134155 return (
135156 < Form { ...form } >
136- < form onSubmit = { form . handleSubmit ( onSubmit ) } >
157+ < form onSubmit = { form . handleSubmit ( onSubmit ) } ref = { containerRef } >
137158 < SettingsCard
138159 header = { {
139160 title : "Apply Coupon" ,
@@ -272,11 +293,7 @@ export function CouponSection(props: { teamId: string | undefined }) {
272293 } ) ;
273294
274295 if ( activeCoupon . isPending ) {
275- return (
276- < div className = "flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50" >
277- < Spinner className = "size-6" />
278- </ div >
279- ) ;
296+ return < LoadingCouponSection /> ;
280297 }
281298
282299 const couponData = optimisticCouponData
@@ -296,17 +313,27 @@ export function CouponSection(props: { teamId: string | undefined }) {
296313 }
297314
298315 return (
299- < ApplyCouponCard
300- teamId = { props . teamId }
301- onCouponApplied = { ( coupon ) => {
302- setOptimisticCouponData ( {
303- type : "added" ,
304- data : coupon ,
305- } ) ;
306- activeCoupon . refetch ( ) . then ( ( ) => {
307- setOptimisticCouponData ( undefined ) ;
308- } ) ;
309- } }
310- />
316+ < Suspense fallback = { < LoadingCouponSection /> } >
317+ < ApplyCouponCard
318+ teamId = { props . teamId }
319+ onCouponApplied = { ( coupon ) => {
320+ setOptimisticCouponData ( {
321+ type : "added" ,
322+ data : coupon ,
323+ } ) ;
324+ activeCoupon . refetch ( ) . then ( ( ) => {
325+ setOptimisticCouponData ( undefined ) ;
326+ } ) ;
327+ } }
328+ />
329+ </ Suspense >
330+ ) ;
331+ }
332+
333+ function LoadingCouponSection ( ) {
334+ return (
335+ < div className = "flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50" >
336+ < Spinner className = "size-6" />
337+ </ div >
311338 ) ;
312339}
0 commit comments