Skip to content

Commit a94f981

Browse files
committed
Show active coupon on billing page (#4917)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on refactoring and enhancing coupon-related components in the `Billing` section of the dashboard. It involves renaming components, improving props handling, and adding new functionalities for coupon application and management. ### Detailed summary - Renamed `CouponCard` to `CouponSection` in `Billing/index.tsx`. - Updated `SettingsCard` to use dynamic class names for buttons. - Added new stories for `CouponDetailsCardUI` and `ApplyCouponCardUI`. - Implemented optimistic updates for coupon application and deletion. - Enhanced `CouponCard` to `ApplyCouponCard` with new props for coupon application. - Introduced `CouponDetailsCardUI` for displaying active coupon details. - Improved error handling and loading states in coupon-related components. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 27375af commit a94f981

File tree

6 files changed

+363
-74
lines changed

6 files changed

+363
-74
lines changed

apps/dashboard/src/@/components/blocks/DangerSettingCard.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import {
1111
DialogTitle,
1212
DialogTrigger,
1313
} from "@/components/ui/dialog";
14+
import { cn } from "../../lib/utils";
1415

1516
export function DangerSettingCard(props: {
1617
title: string;
18+
className?: string;
19+
footerClassName?: string;
1720
description: string;
1821
buttonLabel: string;
1922
buttonOnClick: () => void;
@@ -22,18 +25,31 @@ export function DangerSettingCard(props: {
2225
title: string;
2326
description: string;
2427
};
28+
children?: React.ReactNode;
2529
}) {
2630
return (
27-
<div className="overflow-hidden rounded-lg border border-red-500/70">
28-
<div className="bg-muted/50 px-4 py-6 lg:px-6">
31+
<div
32+
className={cn(
33+
"overflow-hidden rounded-lg border border-red-500/70",
34+
props.className,
35+
)}
36+
>
37+
<div className="px-4 py-6 lg:px-6">
2938
<h3 className="font-semibold text-xl tracking-tight">{props.title}</h3>
3039

3140
<p className="mt-1.5 mb-4 text-foreground text-sm">
3241
{props.description}
3342
</p>
43+
44+
{props.children}
3445
</div>
3546

36-
<div className="flex justify-end border-red-500/70 border-t bg-red-100 px-4 py-4 lg:px-6 dark:bg-red-500/20">
47+
<div
48+
className={cn(
49+
"flex justify-end border-red-500/70 border-t bg-red-100 px-4 py-4 lg:px-6 dark:bg-red-500/20",
50+
props.footerClassName,
51+
)}
52+
>
3753
<Dialog>
3854
<DialogTrigger asChild>
3955
<Button
@@ -46,7 +62,10 @@ export function DangerSettingCard(props: {
4662
</Button>
4763
</DialogTrigger>
4864

49-
<DialogContent>
65+
<DialogContent
66+
className="z-[10001]"
67+
dialogOverlayClassName="z-[10000]"
68+
>
5069
<DialogHeader className="pr-10">
5170
<DialogTitle className="leading-snug">
5271
{props.confirmationDialog.title}

apps/dashboard/src/@/components/blocks/SettingsCard.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ export function SettingsCard(
1717
disabled: boolean;
1818
isPending: boolean;
1919
type?: "submit";
20+
variant?:
21+
| "ghost"
22+
| "default"
23+
| "primary"
24+
| "destructive"
25+
| "outline"
26+
| "secondary";
27+
className?: string;
28+
label?: string;
2029
};
2130
}>,
2231
) {
@@ -58,14 +67,15 @@ export function SettingsCard(
5867
{props.saveButton && !props.noPermissionText && (
5968
<Button
6069
size="sm"
61-
className="gap-2"
70+
className={cn("gap-2", props.saveButton.className)}
6271
onClick={props.saveButton.onClick}
6372
disabled={props.saveButton.disabled || props.saveButton.isPending}
64-
variant="outline"
73+
variant={props.saveButton.variant || "outline"}
6574
type={props.saveButton.type}
6675
>
6776
{props.saveButton.isPending && <Spinner className="size-3" />}
68-
{props.saveButton.isPending ? "Saving" : "Save"}
77+
{props.saveButton.label ||
78+
(props.saveButton.isPending ? "Saving" : "Save")}
6979
</Button>
7080
)}
7181
</div>

apps/dashboard/src/components/settings/Account/Billing/CouponCard.stories.tsx renamed to apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { Meta, StoryObj } from "@storybook/react";
22
import { Toaster } from "sonner";
33
import { BadgeContainer, mobileViewport } from "../../../../stories/utils";
4-
import { CouponCardUI } from "./CouponCard";
4+
import { type ActiveCouponResponse, ApplyCouponCardUI } from "./CouponCard";
55

66
const meta = {
7-
title: "billing/CouponCard",
7+
title: "billing/Coupons/ApplyCoupon",
88
component: Story,
99
parameters: {
1010
nextjs: {
@@ -30,35 +30,70 @@ export const Mobile: Story = {
3030
function statusStub(status: number) {
3131
return async () => {
3232
await new Promise((resolve) => setTimeout(resolve, 1000));
33-
return status;
33+
const data: ActiveCouponResponse | null =
34+
status === 200
35+
? {
36+
id: "xyz",
37+
start: 1727992716,
38+
end: 1759528716,
39+
coupon: {
40+
id: "XYZTEST",
41+
name: "TEST COUPON",
42+
duration: "repeating",
43+
duration_in_months: 12,
44+
},
45+
}
46+
: null;
47+
return {
48+
status,
49+
data,
50+
};
3451
};
3552
}
3653

3754
function Story() {
3855
return (
3956
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
4057
<BadgeContainer label="Success - 200">
41-
<CouponCardUI submit={statusStub(200)} />
58+
<ApplyCouponCardUI
59+
submit={statusStub(200)}
60+
onCouponApplied={undefined}
61+
/>
4262
</BadgeContainer>
4363

4464
<BadgeContainer label="Invalid - 400">
45-
<CouponCardUI submit={statusStub(400)} />
65+
<ApplyCouponCardUI
66+
submit={statusStub(400)}
67+
onCouponApplied={undefined}
68+
/>
4669
</BadgeContainer>
4770

4871
<BadgeContainer label="Not Authorized - 401">
49-
<CouponCardUI submit={statusStub(401)} />
72+
<ApplyCouponCardUI
73+
submit={statusStub(401)}
74+
onCouponApplied={undefined}
75+
/>
5076
</BadgeContainer>
5177

5278
<BadgeContainer label="Already applied - 409">
53-
<CouponCardUI submit={statusStub(409)} />
79+
<ApplyCouponCardUI
80+
submit={statusStub(409)}
81+
onCouponApplied={undefined}
82+
/>
5483
</BadgeContainer>
5584

5685
<BadgeContainer label="Rate Limited - 429">
57-
<CouponCardUI submit={statusStub(429)} />
86+
<ApplyCouponCardUI
87+
submit={statusStub(429)}
88+
onCouponApplied={undefined}
89+
/>
5890
</BadgeContainer>
5991

6092
<BadgeContainer label="Other - 500">
61-
<CouponCardUI submit={statusStub(500)} />
93+
<ApplyCouponCardUI
94+
submit={statusStub(500)}
95+
onCouponApplied={undefined}
96+
/>
6297
</BadgeContainer>
6398
<Toaster richColors />
6499
</div>

0 commit comments

Comments
 (0)