Skip to content

Commit 16245c9

Browse files
committed
add support for disabledAt in DiscountCode table
1 parent f9148c0 commit 16245c9

6 files changed

Lines changed: 96 additions & 25 deletions

File tree

apps/web/app/(ee)/api/stripe/integration/webhook/utils/attribute-via-promotion-code-id.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,21 @@ export async function attributeViaPromotionCodeId({
7070
code: promotionCode.code,
7171
},
7272
},
73-
select: {
73+
include: {
7474
link: true,
7575
},
7676
});
7777

7878
if (!discountCode) {
7979
console.log(
80-
`Couldn't find link associated with promotion code ${promotionCode.code}, skipping...`,
80+
`Couldn't find discount code "${promotionCode.code}" in program "${workspace.defaultProgramId}", skipping...`,
81+
);
82+
return null;
83+
}
84+
85+
if (discountCode.disabledAt) {
86+
console.log(
87+
`Discount code "${discountCode.code}" is disabled, skipping...`,
8188
);
8289
return null;
8390
}

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,12 @@ const PartnerDiscountCodes = ({
333333
{
334334
id: "code",
335335
header: "Code",
336-
cell: ({ row }) => <DiscountCodeBadge code={row.original.code} />,
336+
cell: ({ row }) => (
337+
<DiscountCodeBadge
338+
code={row.original.code}
339+
disabledAt={row.original.disabledAt}
340+
/>
341+
),
337342
},
338343
{
339344
id: "shortLink",

apps/web/lib/discounts/delete-discount-code.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,23 @@ export async function deleteDiscountCodes(
3030
return;
3131
}
3232

33-
if (!isSoftDelete) {
33+
if (isSoftDelete) {
34+
// Soft delete the discount codes from the database (mark them as disabled)
35+
const disabledDiscountCodes = await prisma.discountCode.updateMany({
36+
where: {
37+
id: {
38+
in: discountCodes.map(({ id }) => id),
39+
},
40+
},
41+
data: {
42+
disabledAt: new Date(),
43+
},
44+
});
45+
46+
console.log(
47+
`[deleteDiscountCodes] Disabled ${disabledDiscountCodes.count} discount codes.`,
48+
);
49+
} else {
3450
// Delete the discount codes from the database
3551
const deletedDiscountCodes = await prisma.discountCode.deleteMany({
3652
where: {

apps/web/lib/zod/schemas/discount.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export const DiscountCodeSchema = z.object({
6262
discountId: z.string().nullable(),
6363
partnerId: z.string(),
6464
linkId: z.string(),
65+
disabledAt: z.coerce
66+
.date()
67+
.nullish()
68+
.describe(
69+
"When this discount code was disabled, which happens when a partner is banned or deactivated.",
70+
),
6571
});
6672

6773
export const createDiscountCodeSchema = z.object({

apps/web/prisma/schema/discount.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ model DiscountCode {
3434
linkId String @unique
3535
createdAt DateTime @default(now())
3636
updatedAt DateTime @updatedAt
37+
disabledAt DateTime?
3738
3839
program Program @relation(fields: [programId], references: [id], onDelete: Cascade)
3940
discount Discount? @relation(fields: [discountId], references: [id], onDelete: SetNull)
Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,65 @@
1-
import { Tag, useCopyToClipboard } from "@dub/ui";
1+
import { StatusBadge, Tag, Tooltip, useCopyToClipboard } from "@dub/ui";
22
import { cn } from "@dub/utils";
33
import { toast } from "sonner";
44

5-
export function DiscountCodeBadge({ code }: { code: string }) {
5+
export function DiscountCodeBadge({
6+
code,
7+
disabledAt,
8+
}: {
9+
code: string;
10+
disabledAt?: Date | string | null;
11+
}) {
612
const [copied, copyToClipboard] = useCopyToClipboard();
13+
const isDisabled = !!disabledAt;
14+
715
return (
8-
<button
9-
type="button"
10-
className={cn(
11-
"group/discountcode relative flex w-fit cursor-copy items-center gap-1 rounded-lg bg-green-200 px-2 py-1",
12-
"transition-colors duration-150 hover:bg-green-300/80",
13-
copied && "cursor-default",
16+
<div className="flex items-center gap-2">
17+
<button
18+
type="button"
19+
className={cn(
20+
"group/discountcode relative flex w-fit cursor-copy items-center gap-1 rounded-lg px-2 py-1",
21+
"transition-colors duration-150",
22+
copied && "cursor-default",
23+
isDisabled
24+
? "bg-neutral-200/80 line-through hover:bg-neutral-200/80 hover:no-underline"
25+
: "bg-green-200 hover:bg-green-300/80",
26+
)}
27+
onClick={() =>
28+
copyToClipboard(code, {
29+
onSuccess: () => {
30+
toast.success("Copied discount code to clipboard");
31+
},
32+
})
33+
}
34+
>
35+
<Tag
36+
className={cn(
37+
"size-3",
38+
isDisabled ? "text-neutral-500" : "text-green-700",
39+
)}
40+
strokeWidth={1.5}
41+
/>
42+
<div
43+
className={cn(
44+
"text-xs font-medium decoration-dotted underline-offset-2 transition-colors group-hover/discountcode:underline",
45+
isDisabled ? "text-neutral-600" : "text-green-700",
46+
)}
47+
>
48+
{code}
49+
</div>
50+
</button>
51+
{isDisabled && (
52+
<Tooltip content="This discount code was disabled because the partner was banned or deactivated. To re-enable it, delete this code and create a new one.">
53+
<StatusBadge
54+
variant="neutral"
55+
size="sm"
56+
icon={null}
57+
className="cursor-help"
58+
>
59+
Disabled
60+
</StatusBadge>
61+
</Tooltip>
1462
)}
15-
onClick={() =>
16-
copyToClipboard(code, {
17-
onSuccess: () => {
18-
toast.success("Copied discount code to clipboard");
19-
},
20-
})
21-
}
22-
>
23-
<Tag className="size-3 text-green-700" strokeWidth={1.5} />
24-
<div className="text-xs font-medium text-green-700 decoration-dotted underline-offset-2 transition-colors group-hover/discountcode:underline">
25-
{code}
26-
</div>
27-
</button>
63+
</div>
2864
);
2965
}

0 commit comments

Comments
 (0)