Skip to content

Commit 02db651

Browse files
committed
improve PartnerInfoCards + PartnerStats
1 parent daec20a commit 02db651

2 files changed

Lines changed: 73 additions & 48 deletions

File tree

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/partner-stats.tsx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
1-
import { EnrolledPartnerProps } from "@/lib/types";
2-
import { ArrowUpRight2 } from "@dub/ui";
3-
import { cn, currencyFormatter, nFormatter } from "@dub/utils";
1+
import { EnrolledPartnerExtendedProps } from "@/lib/types";
2+
import { ArrowUpRight2, TimestampTooltip } from "@dub/ui";
3+
import { cn, currencyFormatter, nFormatter, timeAgo } from "@dub/utils";
44
import Link from "next/link";
55
import { useParams } from "next/navigation";
66

77
export function PartnerStats({
88
partner,
99
error,
1010
}: {
11-
partner?: EnrolledPartnerProps;
11+
partner?: EnrolledPartnerExtendedProps;
1212
error?: boolean;
1313
}) {
1414
const { slug } = useParams() as { slug: string };
15+
16+
const lastLeadDate = partner?.lastLeadAt
17+
? new Date(partner.lastLeadAt)
18+
: null;
19+
const lastConversionDate = partner?.lastConversionAt
20+
? new Date(partner.lastConversionAt)
21+
: null;
22+
const approved = partner?.status === "approved";
23+
const leadsLastAt =
24+
approved && lastLeadDate && !Number.isNaN(lastLeadDate.getTime())
25+
? lastLeadDate
26+
: undefined;
27+
const conversionsLastAt =
28+
approved &&
29+
lastConversionDate &&
30+
!Number.isNaN(lastConversionDate.getTime())
31+
? lastConversionDate
32+
: undefined;
33+
1534
return (
1635
<div className="@container/stats">
1736
<div
@@ -46,6 +65,7 @@ export function PartnerStats({
4665
href: partner?.id
4766
? `/${slug}/events?event=leads&partnerId=${partner.id}&interval=1y`
4867
: undefined,
68+
lastAt: leadsLastAt,
4969
},
5070
{
5171
label: "Conversions",
@@ -59,6 +79,7 @@ export function PartnerStats({
5979
href: partner?.id
6080
? `/${slug}/events?event=sales&partnerId=${partner.id}&interval=1y&saleType=new`
6181
: undefined,
82+
lastAt: conversionsLastAt,
6283
},
6384
{
6485
label: "Revenue",
@@ -101,7 +122,7 @@ export function PartnerStats({
101122
? `/${slug}/events?event=sales&partnerId=${partner.id}&interval=1y`
102123
: undefined,
103124
},
104-
].map(({ label, value, href }) => {
125+
].map(({ label, value, href, lastAt }) => {
105126
const As = href ? Link : "div";
106127
return (
107128
<As
@@ -119,6 +140,18 @@ export function PartnerStats({
119140
{value}
120141
</span>
121142
)}
143+
{lastAt ? (
144+
<TimestampTooltip
145+
timestamp={lastAt}
146+
rows={["local", "utc", "unix"]}
147+
side="top"
148+
delayDuration={250}
149+
>
150+
<span className="text-content-muted absolute bottom-3 right-3 max-w-[calc(100%-1.5rem)] cursor-default cursor-help text-right text-[0.6875rem] leading-tight underline decoration-neutral-300/70 decoration-dotted underline-offset-2 hover:decoration-neutral-400">
151+
Last {timeAgo(lastAt, { withAgo: true })}
152+
</span>
153+
</TimestampTooltip>
154+
) : null}
122155
</As>
123156
);
124157
})}

apps/web/ui/partners/partner-info-cards.tsx

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,21 @@ import { usePartnerGroupHistorySheet } from "@/ui/activity-logs/partner-group-hi
1313
import {
1414
Button,
1515
CalendarIcon,
16-
ChartActivity2,
1716
CopyButton,
1817
Globe,
1918
Heart,
2019
OfficeBuilding,
2120
TimestampTooltip,
2221
Trophy,
2322
} from "@dub/ui";
24-
import { VerifiedBadge } from "@dub/ui/icons";
23+
import { TriangleWarning, Users, VerifiedBadge } from "@dub/ui/icons";
2524
import {
2625
COUNTRIES,
2726
fetcher,
2827
formatDate,
2928
formatDateTimeSmart,
30-
timeAgo,
3129
} from "@dub/utils";
30+
import { CircleMinus } from "lucide-react";
3231
import Link from "next/link";
3332
import { Fragment, ReactNode, createElement } from "react";
3433
import useSWR from "swr";
@@ -93,10 +92,7 @@ export function PartnerInfoCards({
9392
const isNetwork = type === "network";
9493

9594
const showPayoutMethodField =
96-
isEnrolled &&
97-
program?.payoutMode !== "external" &&
98-
partner?.payoutsEnabledAt != null &&
99-
partner?.defaultPayoutMethod != null;
95+
isEnrolled && program?.payoutMode !== "external";
10096

10197
const {
10298
partnerGroupHistorySheet,
@@ -143,56 +139,52 @@ export function PartnerInfoCards({
143139
},
144140
];
145141

146-
if (isEnrolled) {
142+
if (isEnrolled && partner) {
147143
basicFields = basicFields.concat([
148-
...(partner?.status === "approved"
149-
? [
150-
{
151-
id: "lastLeadAt",
152-
icon: <ChartActivity2 className="size-3.5" />,
153-
text: partner.lastLeadAt
154-
? `Last lead event ${timeAgo(new Date(partner.lastLeadAt), { withAgo: true })}`
155-
: null,
156-
timestamp: partner.lastLeadAt ?? undefined,
157-
},
158-
{
159-
id: "lastConversionAt",
160-
icon: <ChartActivity2 className="size-3.5" />,
161-
text: partner.lastConversionAt
162-
? `Last conversion event ${timeAgo(new Date(partner.lastConversionAt), { withAgo: true })}`
163-
: null,
164-
timestamp: partner.lastConversionAt ?? undefined,
165-
},
166-
]
167-
: []),
168144
{
169145
id: "createdAt",
170-
icon: <CalendarIcon className="size-3.5" />,
171-
text: partner
172-
? `${partner.status === "approved" ? "Partner since" : "Applied"} ${formatDate(partner.createdAt)}`
173-
: undefined,
174-
timestamp: partner?.createdAt,
146+
icon: <Users className="size-3.5" />,
147+
text: `${partner.status === "approved" ? "Partner since" : "Applied"} ${formatDate(partner.createdAt)}`,
148+
timestamp: partner.createdAt,
175149
},
176-
...(showPayoutMethodField && partner
150+
...(showPayoutMethodField
177151
? [
178152
{
179153
id: "payoutMethod" as const,
180-
icon: createElement(
181-
getPayoutMethodIconConfig(partner.defaultPayoutMethod!).Icon,
182-
{ className: "size-3.5 shrink-0" },
154+
icon: partner.defaultPayoutMethod ? (
155+
createElement(
156+
getPayoutMethodIconConfig(partner.defaultPayoutMethod).Icon,
157+
{ className: "size-3.5 shrink-0" },
158+
)
159+
) : (
160+
<CircleMinus className="size-3.5 shrink-0" />
183161
),
184-
text: `${getPayoutMethodLabel(partner.defaultPayoutMethod!)} connected ${formatDateTimeSmart(partner.payoutsEnabledAt!)}`,
185-
timestamp: partner.payoutsEnabledAt!,
162+
text:
163+
partner.defaultPayoutMethod && partner.payoutsEnabledAt
164+
? `${getPayoutMethodLabel(partner.defaultPayoutMethod)} connected ${formatDateTimeSmart(partner.payoutsEnabledAt)}`
165+
: "No payout method connected",
166+
...(partner.payoutsEnabledAt
167+
? { timestamp: partner.payoutsEnabledAt }
168+
: {}),
186169
},
187170
]
188171
: []),
189-
...(partner?.identityVerifiedAt
172+
// TODO: once more partners verify their identity, we can show this by default
173+
...(partner.identityVerifiedAt
190174
? [
191175
{
192176
id: "identityVerifiedAt",
193-
icon: <VerifiedBadge className="size-3.5 shrink-0" />,
194-
text: `Identity verified ${formatDate(partner.identityVerifiedAt, { month: "short" })}`,
195-
timestamp: partner.identityVerifiedAt,
177+
icon: partner.identityVerifiedAt ? (
178+
<VerifiedBadge className="size-3.5 shrink-0" />
179+
) : (
180+
<TriangleWarning className="size-3.5 shrink-0" />
181+
),
182+
text: partner.identityVerifiedAt
183+
? `Identity verified ${formatDate(partner.identityVerifiedAt, { month: "short" })}`
184+
: "Identity not verified",
185+
...(partner.identityVerifiedAt
186+
? { timestamp: partner.identityVerifiedAt }
187+
: {}),
196188
},
197189
]
198190
: []),

0 commit comments

Comments
 (0)