Skip to content

Commit 1212a00

Browse files
authored
Merge branch 'main' into bulk-partner-invite
2 parents 7354813 + fc244f6 commit 1212a00

File tree

27 files changed

+507
-93
lines changed

27 files changed

+507
-93
lines changed

apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export async function POST(req: Request) {
3636
stripeConnectId: stripeAccount,
3737
},
3838
select: {
39+
id: true,
3940
email: true,
4041
},
4142
});
@@ -156,17 +157,29 @@ export async function POST(req: Request) {
156157
limit: 100,
157158
});
158159

159-
// update all payouts that match the following criteria to have the stripePayoutId:
160+
// update all payouts for the partner that match the following criteria to have the stripePayoutId:
160161
// - in the "sent" status
161-
// - have a stripe transfer id (meaning it was transferred to this connected account)
162162
// - no stripe payout id (meaning it was not yet withdrawn to the connected bank account)
163+
// - have a stripe transfer id (meaning it was transferred to this connected account)
164+
// OR: payouts that are in the "failed" status + have a stripePayoutId (failed to send before)
163165
const updatedPayouts = await prisma.payout.updateMany({
164166
where: {
165-
status: "sent",
166-
stripePayoutId: null,
167-
stripeTransferId: {
168-
in: transfers.data.map(({ id }) => id),
169-
},
167+
partnerId: partner.id,
168+
OR: [
169+
{
170+
status: "sent",
171+
stripePayoutId: null,
172+
stripeTransferId: {
173+
in: transfers.data.map(({ id }) => id),
174+
},
175+
},
176+
{
177+
status: "failed",
178+
stripePayoutId: {
179+
not: null,
180+
},
181+
},
182+
],
170183
},
171184
data: {
172185
stripePayoutId: stripePayout.id,

apps/web/app/(ee)/api/network/programs/route.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,19 +113,23 @@ export const GET = withPartnerProfile(async ({ partner, searchParams }) => {
113113

114114
return NextResponse.json(
115115
z.array(NetworkProgramSchema).parse(
116-
programs.map((program) => ({
117-
...program,
118-
rewards:
119-
program.groups.length > 0
120-
? [
121-
program.groups[0].clickReward,
122-
program.groups[0].leadReward,
123-
program.groups[0].saleReward,
124-
].filter(Boolean)
125-
: [],
126-
discount: program.groups.length > 0 ? program.groups[0].discount : null,
127-
categories: program.categories.map(({ category }) => category),
128-
})),
116+
programs
117+
// if requesting featured programs, randomize the order
118+
.sort(() => (featured ? Math.random() - 0.5 : 0))
119+
.map((program) => ({
120+
...program,
121+
rewards:
122+
program.groups.length > 0
123+
? [
124+
program.groups[0].clickReward,
125+
program.groups[0].leadReward,
126+
program.groups[0].saleReward,
127+
].filter(Boolean)
128+
: [],
129+
discount:
130+
program.groups.length > 0 ? program.groups[0].discount : null,
131+
categories: program.categories.map(({ category }) => category),
132+
})),
129133
),
130134
);
131135
});

apps/web/app/(ee)/api/track/open/route.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const POST = withAxiom(async (req) => {
2929
const identityHash = await getIdentityHash(req);
3030

3131
if (!deepLinkUrl) {
32+
// Probabilistic IP-based tracking
3233
if (ip) {
3334
// if ip address is present, check if there's a cached click
3435
console.log(`Checking cache for ${ip}:${dubDomain}:*`);
@@ -105,9 +106,16 @@ export const POST = withAxiom(async (req) => {
105106
});
106107
}
107108

109+
const linkData = {
110+
id: cachedLink.id,
111+
domain,
112+
key,
113+
url: cachedLink.url,
114+
};
115+
108116
// if there's no cached clickId, track the click event
109117
if (!cachedClickId) {
110-
await recordClick({
118+
const clickData = await recordClick({
111119
req,
112120
clickId,
113121
workspaceId: cachedLink.projectId,
@@ -121,16 +129,22 @@ export const POST = withAxiom(async (req) => {
121129
shouldCacheClickId: true,
122130
trigger: "deeplink",
123131
});
132+
133+
// return early with clickId = null if no click data was recorded (bot detected)
134+
if (!clickData) {
135+
return NextResponse.json(
136+
trackOpenResponseSchema.parse({
137+
clickId: null,
138+
link: linkData,
139+
}),
140+
{ headers: COMMON_CORS_HEADERS },
141+
);
142+
}
124143
}
125144

126145
const response = trackOpenResponseSchema.parse({
127146
clickId,
128-
link: {
129-
id: cachedLink.id,
130-
domain,
131-
key,
132-
url: cachedLink.url,
133-
},
147+
link: linkData,
134148
});
135149

136150
return NextResponse.json(response, { headers: COMMON_CORS_HEADERS });

apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/marketplace/[programSlug]/page.tsx

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { ProgramCategory } from "@/ui/partners/program-marketplace/program-categ
88
import { ProgramRewardsDisplay } from "@/ui/partners/program-marketplace/program-rewards-display";
99
import { prisma } from "@dub/prisma";
1010
import { ChevronRight, Shop, Tooltip } from "@dub/ui";
11-
import { OG_AVATAR_URL, cn } from "@dub/utils";
11+
import { Globe } from "@dub/ui/icons";
12+
import { OG_AVATAR_URL, cn, getDomainWithoutWWW } from "@dub/utils";
1213
import Link from "next/link";
1314
import { redirect } from "next/navigation";
1415
import { ProgramStatusBadge } from "../program-status-badge";
@@ -128,7 +129,9 @@ export default async function MarketplaceProgramPage(props: {
128129
<span
129130
className={cn(
130131
"block text-xs font-medium",
131-
isDarkImage && "text-content-inverted/70",
132+
isDarkImage
133+
? "text-content-inverted"
134+
: "text-neutral-400",
132135
)}
133136
>
134137
Rewards
@@ -147,7 +150,9 @@ export default async function MarketplaceProgramPage(props: {
147150
<span
148151
className={cn(
149152
"block text-xs font-medium",
150-
isDarkImage && "text-content-inverted/70",
153+
isDarkImage
154+
? "text-content-inverted"
155+
: "text-neutral-400",
151156
)}
152157
>
153158
Category
@@ -191,6 +196,29 @@ export default async function MarketplaceProgramPage(props: {
191196
</div>
192197
</div>
193198
)}
199+
{program.url && (
200+
<div className="min-w-0">
201+
<span className="block text-xs font-medium text-neutral-400">
202+
Website
203+
</span>
204+
<Link
205+
href={program.url}
206+
target="_blank"
207+
rel="noopener noreferrer"
208+
className={cn(
209+
"mt-1 flex max-w-[220px] items-center gap-1.5 text-sm font-medium",
210+
isDarkImage
211+
? "text-content-inverted/90 hover:text-content-inverted"
212+
: "text-content-default hover:text-content-emphasis",
213+
)}
214+
>
215+
<Globe className="size-4 shrink-0" />
216+
<span className="truncate">
217+
{getDomainWithoutWWW(program.url)}
218+
</span>
219+
</Link>
220+
</div>
221+
)}
194222
</div>
195223
</div>
196224
</div>

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/overview-tasks.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { usePartnerMessagesCount } from "@/lib/swr/use-partner-messages-count";
22
import usePartnersCount from "@/lib/swr/use-partners-count";
3-
import usePayoutsCount from "@/lib/swr/use-payouts-count";
3+
import { usePayoutsCount } from "@/lib/swr/use-payouts-count";
44
import useWorkspace from "@/lib/swr/use-workspace";
55
import { ProgramOverviewCard } from "@/ui/partners/overview/program-overview-card";
66
import { MoneyBills2, Msgs, UserCheck } from "@dub/ui";
@@ -21,6 +21,7 @@ export function OverviewTasks() {
2121
} = usePayoutsCount<number | undefined>({
2222
eligibility: "eligible",
2323
status: "pending",
24+
ignoreParams: true,
2425
});
2526

2627
const { count: unreadMessagesCount, isLoading: unreadMessagesLoading } =

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-stats.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { clientAccessCheck } from "@/lib/client-access-check";
4-
import usePayoutsCount from "@/lib/swr/use-payouts-count";
4+
import { usePayoutsCount } from "@/lib/swr/use-payouts-count";
55
import useWorkspace from "@/lib/swr/use-workspace";
66
import { PayoutsCount } from "@/lib/types";
77
import { ConfirmPayoutsSheet } from "@/ui/partners/confirm-payouts-sheet";

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-table.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { getPlanCapabilities } from "@/lib/plan-capabilities";
44
import { useFraudGroupCount } from "@/lib/swr/use-fraud-groups-count";
5-
import usePayoutsCount from "@/lib/swr/use-payouts-count";
5+
import { usePayoutsCount } from "@/lib/swr/use-payouts-count";
66
import useProgram from "@/lib/swr/use-program";
77
import useWorkspace from "@/lib/swr/use-workspace";
88
import { FraudGroupCountByPartner, PayoutResponse } from "@/lib/types";

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/use-payout-filters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import usePartners from "@/lib/swr/use-partners";
2-
import usePayoutsCount from "@/lib/swr/use-payouts-count";
2+
import { usePayoutsCount } from "@/lib/swr/use-payouts-count";
33
import { EnrolledPartnerProps, PayoutsCount } from "@/lib/types";
44
import { PayoutStatusBadges } from "@/ui/partners/payout-status-badges";
55
import { useRouterStuff } from "@dub/ui";

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/billing/plan-usage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ export default function PlanUsage() {
7171
const { users } = useWorkspaceUsers();
7272

7373
const { partnersCount } = usePartnersCount<number>({
74-
programId: defaultProgramId ?? undefined,
7574
status: "approved",
7675
ignoreParams: true,
76+
enabled: Boolean(defaultProgramId),
7777
});
7878

7979
const { groupsCount } = useGroupsCount();

apps/web/app/app.dub.co/(dashboard)/[slug]/links/page-client.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,7 @@ function WorkspaceLinks() {
228228
</div>
229229

230230
{isLoading ? (
231-
<div className="flex grow-0 animate-pulse items-center space-x-2">
232-
<div className="h-10 w-24 rounded-md bg-neutral-200" />
233-
<div className="h-10 w-10 rounded-md bg-neutral-200" />
234-
</div>
231+
<div className="h-10 w-[2.125rem] animate-pulse rounded-md bg-neutral-200" />
235232
) : canCreateLinks ? (
236233
<MoreLinkOptions />
237234
) : (

0 commit comments

Comments
 (0)