Skip to content

Commit 6a80c87

Browse files
committed
Filter payouts by date range (using paidAt)
1 parent 13d8f1a commit 6a80c87

File tree

7 files changed

+67
-23
lines changed

7 files changed

+67
-23
lines changed

apps/web/app/api/programs/[programId]/payouts/count/route.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
12
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
23
import { withWorkspace } from "@/lib/auth";
34
import { MIN_PAYOUT_AMOUNT } from "@/lib/partners/constants";
@@ -10,14 +11,17 @@ import { NextResponse } from "next/server";
1011
export const GET = withWorkspace(
1112
async ({ workspace, params, searchParams }) => {
1213
const { programId } = params;
13-
const { partnerId, groupBy, eligibility } =
14-
payoutsCountQuerySchema.parse(searchParams);
14+
const parsed = payoutsCountQuerySchema.parse(searchParams);
1515

1616
await getProgramOrThrow({
1717
workspaceId: workspace.id,
1818
programId,
1919
});
2020

21+
const { startDate, endDate } = getStartEndDates(parsed);
22+
23+
const { partnerId, groupBy, eligibility, status } = parsed;
24+
2125
const where: Prisma.PayoutWhereInput = {
2226
programId,
2327
...(partnerId && { partnerId }),
@@ -29,6 +33,10 @@ export const GET = withWorkspace(
2933
payoutsEnabled: true,
3034
},
3135
}),
36+
paidAt: {
37+
gte: startDate.toISOString(),
38+
lte: endDate.toISOString(),
39+
},
3240
};
3341

3442
// Get payout count by status
@@ -61,7 +69,10 @@ export const GET = withWorkspace(
6169
return NextResponse.json(counts);
6270
} else {
6371
const count = await prisma.payout.count({
64-
where,
72+
where: {
73+
...where,
74+
status,
75+
},
6576
});
6677

6778
return NextResponse.json(count);

apps/web/app/api/programs/[programId]/payouts/route.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
12
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
23
import { withWorkspace } from "@/lib/auth";
34
import {
@@ -12,21 +13,28 @@ import z from "zod";
1213
export const GET = withWorkspace(
1314
async ({ workspace, params, searchParams }) => {
1415
const { programId } = params;
16+
const parsed = payoutsQuerySchema.parse(searchParams);
17+
18+
await getProgramOrThrow({
19+
workspaceId: workspace.id,
20+
programId,
21+
});
22+
1523
const {
1624
status,
1725
partnerId,
1826
invoiceId,
27+
type,
1928
sortBy,
2029
sortOrder,
2130
page,
2231
pageSize,
23-
type,
24-
} = payoutsQuerySchema.parse(searchParams);
32+
} = parsed;
2533

26-
await getProgramOrThrow({
27-
workspaceId: workspace.id,
28-
programId,
29-
});
34+
console.log(parsed);
35+
36+
const { startDate, endDate } = getStartEndDates(parsed);
37+
console.log({ startDate, endDate });
3038

3139
const payouts = await prisma.payout.findMany({
3240
where: {
@@ -35,6 +43,10 @@ export const GET = withWorkspace(
3543
...(partnerId && { partnerId }),
3644
...(type && { type }),
3745
...(invoiceId && { invoiceId }),
46+
paidAt: {
47+
gte: startDate.toISOString(),
48+
lte: endDate.toISOString(),
49+
},
3850
},
3951
include: {
4052
partner: true,

apps/web/app/api/stripe/webhook/charge-succeeded.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export async function chargeSucceeded(event: Stripe.Event) {
7575
data: {
7676
stripeTransferId: transfer.id,
7777
status: "completed",
78+
paidAt: new Date(),
7879
},
7980
});
8081

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import usePayoutsCount from "@/lib/swr/use-payouts-count";
4+
import useWorkspace from "@/lib/swr/use-workspace";
45
import { PayoutResponse } from "@/lib/types";
56
import { AmountRowItem } from "@/ui/partners/amount-row-item";
67
import { PartnerRowItem } from "@/ui/partners/partner-row-item";
@@ -22,7 +23,7 @@ import {
2223
useTable,
2324
} from "@dub/ui";
2425
import { Dots, MoneyBill2, MoneyBills2 } from "@dub/ui/icons";
25-
import { cn, formatDate } from "@dub/utils";
26+
import { cn, formatDate, timeAgo } from "@dub/utils";
2627
import { fetcher } from "@dub/utils/src/functions/fetcher";
2728
import { Row } from "@tanstack/react-table";
2829
import { Command } from "cmdk";
@@ -33,7 +34,8 @@ import { usePayoutFilters } from "./use-payout-filters";
3334

3435
export function PayoutTable() {
3536
const { programId } = useParams();
36-
const { queryParams, searchParams } = useRouterStuff();
37+
const { id: workspaceId } = useWorkspace();
38+
const { queryParams, searchParams, getQueryString } = useRouterStuff();
3739

3840
const sortBy = searchParams.get("sortBy") || "periodStart";
3941
const sortOrder = searchParams.get("sortOrder") === "asc" ? "asc" : "desc";
@@ -44,7 +46,6 @@ export function PayoutTable() {
4446
onSelect,
4547
onRemove,
4648
onRemoveAll,
47-
searchQuery,
4849
isFiltered,
4950
setSearch,
5051
setSelectedFilter,
@@ -57,7 +58,7 @@ export function PayoutTable() {
5758
error,
5859
isLoading,
5960
} = useSWR<PayoutResponse[]>(
60-
`/api/programs/${programId}/payouts?${searchQuery}`,
61+
`/api/programs/${programId}/payouts?${getQueryString({ workspaceId })}`,
6162
fetcher,
6263
{
6364
keepPreviousData: true,
@@ -128,7 +129,7 @@ export function PayoutTable() {
128129
id: "paidAt",
129130
header: "Paid at",
130131
cell: ({ row }) =>
131-
row.original.paidAt ? formatDate(row.original.paidAt) : "-",
132+
row.original.paidAt ? timeAgo(row.original.paidAt) : "-",
132133
},
133134
{
134135
id: "amount",

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { useDebounce } from "use-debounce";
1414
export function usePayoutFilters(extraSearchParams: Record<string, string>) {
1515
const { searchParamsObj, queryParams } = useRouterStuff();
1616
const { id: workspaceId } = useWorkspace();
17+
const { interval, start, end } = searchParamsObj;
18+
1719
const { payoutsCount } = usePayoutsCount<PayoutsCount[]>({
1820
groupBy: "status",
1921
});
@@ -82,6 +84,9 @@ export function usePayoutFilters(extraSearchParams: Record<string, string>) {
8284
return [
8385
...(status ? [{ key: "status", value: status }] : []),
8486
...(partnerId ? [{ key: "partnerId", value: partnerId }] : []),
87+
...(interval ? [{ key: "interval", value: interval }] : []),
88+
...(start ? [{ key: "start", value: start }] : []),
89+
...(end ? [{ key: "end", value: end }] : []),
8590
];
8691
}, [searchParamsObj]);
8792

@@ -109,14 +114,13 @@ export function usePayoutFilters(extraSearchParams: Record<string, string>) {
109114
...Object.fromEntries(
110115
activeFilters.map(({ key, value }) => [key, value]),
111116
),
112-
...(searchParamsObj.search && { search: searchParamsObj.search }),
113117
workspaceId: workspaceId || "",
114118
...extraSearchParams,
115119
}).toString(),
116120
[activeFilters, workspaceId, extraSearchParams],
117121
);
118122

119-
const isFiltered = activeFilters.length > 0 || searchParamsObj.search;
123+
const isFiltered = activeFilters.length > 0;
120124

121125
return {
122126
filters,

apps/web/lib/swr/use-payouts-count.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useRouterStuff } from "@dub/ui";
12
import { fetcher } from "@dub/utils";
23
import { useParams } from "next/navigation";
34
import useSWR from "swr";
@@ -11,13 +12,14 @@ export default function usePayoutsCount<T>(
1112
) {
1213
const { programId } = useParams();
1314
const { id: workspaceId } = useWorkspace();
15+
const { getQueryString } = useRouterStuff();
1416

1517
const { data: payoutsCount, error } = useSWR<PayoutsCount[]>(
1618
workspaceId &&
17-
`/api/programs/${programId}/payouts/count?${new URLSearchParams({
19+
`/api/programs/${programId}/payouts/count?${getQueryString({
1820
...opts,
1921
workspaceId,
20-
}).toString()}`,
22+
})}`,
2123
fetcher,
2224
);
2325

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { intervals } from "@/lib/analytics/constants";
12
import { parseDateSchema } from "@/lib/zod/schemas/utils";
23
import { PayoutStatus, PayoutType } from "@dub/prisma/client";
34
import { z } from "zod";
@@ -30,14 +31,26 @@ export const payoutsQuerySchema = z
3031
sortBy: z.enum(["periodStart", "total"]).default("periodStart"),
3132
sortOrder: z.enum(["asc", "desc"]).default("desc"),
3233
type: z.nativeEnum(PayoutType).optional(),
34+
interval: z.enum(intervals).default("1y").optional(),
35+
start: parseDateSchema.optional(),
36+
end: parseDateSchema.optional(),
3337
})
3438
.merge(getPaginationQuerySchema({ pageSize: PAYOUTS_MAX_PAGE_SIZE }));
3539

36-
export const payoutsCountQuerySchema = z.object({
37-
partnerId: z.string().optional(),
38-
groupBy: z.enum(["status"]).optional(),
39-
eligibility: z.enum(["eligible"]).optional(),
40-
});
40+
export const payoutsCountQuerySchema = payoutsQuerySchema
41+
.pick({
42+
status: true,
43+
partnerId: true,
44+
interval: true,
45+
start: true,
46+
end: true,
47+
})
48+
.merge(
49+
z.object({
50+
groupBy: z.enum(["status"]).optional(),
51+
eligibility: z.enum(["eligible"]).optional(),
52+
}),
53+
);
4154

4255
export const PayoutSchema = z.object({
4356
id: z.string(),

0 commit comments

Comments
 (0)