Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ function statusStub(status: number) {
function Story() {
return (
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
<BadgeContainer label="Prefill code - XYZ, Success - 200">
<ApplyCouponCardUI
submit={statusStub(200)}
onCouponApplied={undefined}
prefillPromoCode="XYZ"
/>
</BadgeContainer>

<BadgeContainer label="Success - 200">
<ApplyCouponCardUI
submit={statusStub(200)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery } from "@tanstack/react-query";
import { format, fromUnixTime } from "date-fns";
import { TagIcon } from "lucide-react";
import { useState } from "react";
import { useSearchParams } from "next/navigation";
import { Suspense, useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -37,9 +38,13 @@ function ApplyCouponCard(props: {
teamId: string | undefined;
onCouponApplied: (data: ActiveCouponResponse) => void;
}) {
const searchParams = useSearchParams();
const couponCode = searchParams?.get("coupon");
return (
<ApplyCouponCardUI
onCouponApplied={props.onCouponApplied}
prefillPromoCode={couponCode || undefined}
scrollIntoView={!!couponCode}
submit={async (promoCode: string) => {
const res = await fetch("/api/server-proxy/api/v1/coupons/redeem", {
method: "POST",
Expand Down Expand Up @@ -79,14 +84,30 @@ export function ApplyCouponCardUI(props: {
data: null | ActiveCouponResponse;
}>;
onCouponApplied: ((data: ActiveCouponResponse) => void) | undefined;
prefillPromoCode?: string;
scrollIntoView?: boolean;
}) {
const containerRef = useRef<HTMLFormElement | null>(null);
const form = useForm<z.infer<typeof couponFormSchema>>({
resolver: zodResolver(couponFormSchema),
defaultValues: {
promoCode: "",
promoCode: props.prefillPromoCode,
},
});

const scrolled = useRef(false);
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
if (props.scrollIntoView && !scrolled.current) {
const el = containerRef.current;
if (el) {
el.scrollIntoView({ behavior: "smooth", block: "start" });
el.querySelector("input")?.focus();
scrolled.current = true;
}
}
}, [props.scrollIntoView]);

const applyCoupon = useMutation({
mutationFn: (promoCode: string) => props.submit(promoCode),
});
Expand Down Expand Up @@ -133,7 +154,7 @@ export function ApplyCouponCardUI(props: {

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<form onSubmit={form.handleSubmit(onSubmit)} ref={containerRef}>
<SettingsCard
header={{
title: "Apply Coupon",
Expand Down Expand Up @@ -272,11 +293,7 @@ export function CouponSection(props: { teamId: string | undefined }) {
});

if (activeCoupon.isPending) {
return (
<div className="flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50">
<Spinner className="size-6" />
</div>
);
return <LoadingCouponSection />;
}

const couponData = optimisticCouponData
Expand All @@ -296,17 +313,27 @@ export function CouponSection(props: { teamId: string | undefined }) {
}

return (
<ApplyCouponCard
teamId={props.teamId}
onCouponApplied={(coupon) => {
setOptimisticCouponData({
type: "added",
data: coupon,
});
activeCoupon.refetch().then(() => {
setOptimisticCouponData(undefined);
});
}}
/>
<Suspense fallback={<LoadingCouponSection />}>
<ApplyCouponCard
teamId={props.teamId}
onCouponApplied={(coupon) => {
setOptimisticCouponData({
type: "added",
data: coupon,
});
activeCoupon.refetch().then(() => {
setOptimisticCouponData(undefined);
});
}}
/>
</Suspense>
);
}

function LoadingCouponSection() {
return (
<div className="flex h-[300px] items-center justify-center rounded-lg border border-border bg-muted/50">
<Spinner className="size-6" />
</div>
);
}
Loading