Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Form } from "./form";

export default async function ProgramOnboardingRewardsPage() {
return (
<StepPage title="Configure rewards">
<StepPage title="Create default reward">
<Form />
</StepPage>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,15 @@ import type { DiscountProps, GroupProps } from "@/lib/types";
import { DEFAULT_PARTNER_GROUP } from "@/lib/zod/schemas/groups";
import { useDiscountSheet } from "@/ui/partners/discounts/add-edit-discount-sheet";
import { ProgramRewardDescription } from "@/ui/partners/program-reward-description";
import { X } from "@/ui/shared/icons";
import {
Button,
buttonVariants,
Discount,
Grid,
useLocalStorage,
} from "@dub/ui";
import { Button } from "@dub/ui";
import { cn, isClickOnInteractiveChild } from "@dub/utils";
import { BadgePercent } from "lucide-react";
import { motion } from "motion/react";

export const GroupDiscounts = () => {
const { group, loading } = useGroup();

return (
<div>
<Banner />

{loading || !group ? (
<DiscountSkeleton />
) : (
Expand Down Expand Up @@ -132,77 +122,3 @@ const DiscountSkeleton = () => {
);
};

const Banner = () => {
const [dismissedBanner, setDismissedBanner] = useLocalStorage<boolean>(
"program-discount-banner-dismissed",
false,
);

return (
<motion.div
animate={
dismissedBanner
? { opacity: 0, height: 0 }
: { opacity: 1, height: "auto" }
}
initial={false}
className="overflow-hidden"
inert={dismissedBanner}
>
<div className="pb-6">
<div className="relative isolate overflow-hidden rounded-xl bg-neutral-100">
<div
className="pointer-events-none absolute inset-0 [mask-image:linear-gradient(90deg,transparent,black)]"
aria-hidden
>
<div className="absolute right-0 top-0 h-full w-[600px]">
<Grid
cellSize={60}
patternOffset={[1, -30]}
className="text-neutral-200"
/>
</div>
<div className="absolute -inset-16 opacity-15 blur-[50px] [transform:translateZ(0)]">
<div
className="absolute right-0 top-0 h-full w-[350px] -scale-y-100 rounded-l-full saturate-150"
style={{
backgroundImage: `conic-gradient(from -66deg, #855AFC -32deg, #FF0000 63deg, #EAB308 158deg, #5CFF80 240deg, #855AFC 328deg, #FF0000 423deg)`,
}}
/>
</div>
</div>
<div className="relative flex flex-col gap-4 p-5">
<Discount className="size-6" />
<div>
<h2 className="text-content-emphasis text-base font-semibold">
Referral discounts
</h2>
<p className="text-content-subtle text-base font-normal leading-6">
Discounts offered to customers when referred by partners in this
group
</p>
</div>
<a
href="https://dub.co/help/article/dual-sided-incentives"
target="_blank"
className={cn(
buttonVariants({ variant: "secondary" }),
"flex h-8 w-fit items-center rounded-lg border bg-white px-3 text-sm",
)}
>
Learn more
</a>
</div>

<button
type="button"
className="text-content-emphasis absolute right-4 top-4 flex size-7 items-center justify-center rounded-lg transition-colors duration-150 hover:bg-black/5 active:bg-black/10"
onClick={() => setDismissedBanner(true)}
>
<X className="size-4" />
</button>
</div>
</div>
</motion.div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,31 @@ import {
RewardSheet,
useRewardSheet,
} from "@/ui/partners/rewards/add-edit-reward-sheet";
import { X } from "@/ui/shared/icons";
import { EventType } from "@dub/prisma/client";
import {
Button,
buttonVariants,
Gift,
Grid,
useLocalStorage,
useRouterStuff,
} from "@dub/ui";
import { Button, useRouterStuff } from "@dub/ui";
import { cn } from "@dub/utils";
import { motion } from "motion/react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useEffect, useState } from "react";

const REWARD_EVENT_DESCRIPTIONS: Record<
EventType,
{ title: string; description: string }
> = {
sale: {
title: "Sale reward",
description: "Reward when revenue is generated",
},
lead: {
title: "Lead reward",
description: "Reward for sign ups or demos",
},
click: {
title: "Click reward",
description: "Reward for traffic and reach",
},
};

export function GroupRewards() {
const { group, loading } = useGroup();
const { searchParams } = useRouterStuff();
Expand Down Expand Up @@ -69,8 +78,6 @@ export function GroupRewards() {
/>
)}

<Banner />

<div className="flex flex-col gap-6">
{loading || !group ? (
<>
Expand Down Expand Up @@ -157,18 +164,23 @@ const RewardItem = ({
</div>
<div className="flex flex-1 flex-col justify-between gap-y-4 md:flex-row md:items-center">
<div className="flex items-center gap-2">
<span className="text-sm font-normal">
{reward ? (
{reward ? (
<span className="text-sm font-normal">
<ProgramRewardDescription
reward={reward}
amountClassName="text-blue-600"
/>
) : (
<span className="text-sm font-normal text-neutral-600">
No {event} reward configured
</span>
) : (
<div className="flex flex-col">
<span className="text-sm font-medium text-neutral-900">
{REWARD_EVENT_DESCRIPTIONS[event].title}
</span>
)}
</span>
<span className="text-sm font-normal text-neutral-500">
{REWARD_EVENT_DESCRIPTIONS[event].description}
</span>
</div>
)}
</div>

{reward ? (
Expand Down Expand Up @@ -251,76 +263,3 @@ const RewardSkeleton = () => {
);
};

const Banner = () => {
const [dismissedBanner, setDismissedBanner] = useLocalStorage<boolean>(
"program-rewards-banner-dismissed",
false,
);

return (
<motion.div
animate={
dismissedBanner
? { opacity: 0, height: 0 }
: { opacity: 1, height: "auto" }
}
initial={false}
className="overflow-hidden"
inert={dismissedBanner}
>
<div className="pb-6">
<div className="relative isolate overflow-hidden rounded-xl bg-neutral-100">
<div
className="pointer-events-none absolute inset-0 [mask-image:linear-gradient(90deg,transparent,black)]"
aria-hidden
>
<div className="absolute right-0 top-0 h-full w-[600px]">
<Grid
cellSize={60}
patternOffset={[1, -30]}
className="text-neutral-200"
/>
</div>
<div className="absolute -inset-16 opacity-15 blur-[50px] [transform:translateZ(0)]">
<div
className="absolute right-0 top-0 h-full w-[350px] -scale-y-100 rounded-l-full saturate-150"
style={{
backgroundImage: `conic-gradient(from -66deg, #855AFC -32deg, #FF0000 63deg, #EAB308 158deg, #5CFF80 240deg, #855AFC 328deg, #FF0000 423deg)`,
}}
/>
</div>
</div>
<div className="relative flex flex-col gap-4 p-5">
<Gift className="size-6" />
<div>
<h2 className="text-content-emphasis text-base font-semibold">
Rewards
</h2>
<p className="text-content-subtle text-base font-normal leading-6">
Rewards offered to all partners enrolled in this group
</p>
</div>
<a
href="https://dub.co/help/article/partner-rewards"
target="_blank"
className={cn(
buttonVariants({ variant: "secondary" }),
"flex h-8 w-fit items-center rounded-lg border bg-white px-3 text-sm",
)}
>
Learn more
</a>
</div>

<button
type="button"
className="text-content-emphasis absolute right-4 top-4 flex size-7 items-center justify-center rounded-lg transition-colors duration-150 hover:bg-black/5 active:bg-black/10"
onClick={() => setDismissedBanner(true)}
>
<X className="size-4" />
</button>
</div>
</div>
</motion.div>
);
};
Loading
Loading