Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 1 addition & 3 deletions .github/workflows/playwright.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ jobs:
QSTASH_CURRENT_SIGNING_KEY: "xx"
QSTASH_NEXT_SIGNING_KEY: "xx"

AXIOM_TOKEN: ""
AXIOM_DATASET: ""

# RESEND_API_KEY must be unset so emails route through SMTP to MailHog
SMTP_HOST: "localhost"
SMTP_PORT: "1025"
Expand All @@ -70,6 +67,7 @@ jobs:
STRIPE_APP_SECRET_KEY_TEST: "xx"
STRIPE_CONNECT_V2_WEBHOOK_SECRET: "xx"
STRIPE_APP_SECRET_KEY_SANDBOX: "xx"
STRIPE_APP_SECRET_KEY: "xx"

services:
mysql:
Expand Down
41 changes: 19 additions & 22 deletions apps/web/app/(ee)/api/admin/payouts/stablecoin/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,26 @@ export const GET = withAdmin(async ({ searchParams }) => {
where: {
...(status && { status }),
...(programId && { programId }),
partner: {
defaultPayoutMethod: "stablecoin",
stripeRecipientId: {
not: null,
OR: [
{
method: "stablecoin",
},
cryptoWalletAddress: {
not: null,
{
status: "pending",
partner: {
stripeRecipientId: {
not: null,
},
cryptoWalletAddress: {
not: null,
},
payoutsEnabledAt: {
not: null,
},
...(country && { country }),
},
},
payoutsEnabledAt: {
not: null,
},
...(country && { country }),
},
],
},
orderBy: {
amount: "desc",
Expand All @@ -66,17 +73,7 @@ export const GET = withAdmin(async ({ searchParams }) => {
.parse(
payouts.filter(
(payout) =>
(
payout as typeof payout & {
program?: { minPayoutAmount: number };
}
).program &&
payout.amount >=
(
payout as typeof payout & {
program: { minPayoutAmount: number };
}
).program.minPayoutAmount,
payout.program && payout.amount >= payout.program.minPayoutAmount,
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AnalyticsFunnelChart } from "@/ui/analytics/analytics-funnel-chart";
import { AnalyticsContext } from "@/ui/analytics/analytics-provider";
import { AnalyticsTabs } from "@/ui/analytics/analytics-tabs";
import { ChartViewSwitcher } from "@/ui/analytics/chart-view-switcher";
import { useRouterStuff } from "@dub/ui";
import { ToggleGroup, useRouterStuff } from "@dub/ui";
import { LoadingSpinner } from "@dub/ui/icons";
import { fetcher } from "@dub/utils";
import { useContext, useMemo } from "react";
Expand Down Expand Up @@ -89,7 +89,30 @@ export function AnalyticsChart() {
) : (
<AnalyticsFunnelChart />
)}
<ChartViewSwitcher className="absolute right-3 top-3" />
<div className="absolute right-3 top-3 flex items-center gap-2">
<ToggleGroup
className="flex w-fit shrink-0 items-center gap-1 border-neutral-100 bg-neutral-100 sm:hidden"
optionClassName="size-8 p-0 flex items-center justify-center"
indicatorClassName="border border-neutral-200 bg-white"
options={[
{
label: <div className="text-base">$</div>,
value: "saleAmount",
},
{
label: <div className="text-[11px]">123</div>,
value: "sales",
},
]}
selected={saleUnit}
selectAction={(option) =>
queryParams({
set: { saleUnit: option },
})
}
/>
<ChartViewSwitcher />
</div>
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,34 +89,46 @@ export function ProgramAnalyticsPageClient() {
programPage: true,
});

const filterSelect = (
<Filter.Select
className="w-full md:w-fit"
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
onOpenFilter={onOpenFilter}
isAdvancedFilter
askAI
/>
);

const dateRangePicker = (
<SimpleDateRangePicker align="start" className="w-full md:w-fit" />
);

return (
<div className="flex flex-col gap-3 pb-12">
<div>
<div className="flex items-center gap-2">
<Filter.Select
className="w-full md:w-fit"
filters={filters}
activeFilters={activeFilters}
onSelect={onSelect}
onRemove={onRemove}
onOpenFilter={onOpenFilter}
isAdvancedFilter
askAI
/>
<SimpleDateRangePicker align="start" className="w-fit" />
<div className="flex grow justify-end gap-2">
<Link
href={`/${slug}/events${getQueryString({ folderId: program?.defaultFolderId, event: selectedTab, interval })}`}
>
<Button
variant="secondary"
className="w-fit"
icon={
<SquareLayoutGrid6 className="h-4 w-4 text-neutral-600" />
}
text={isMobile ? undefined : "View Events"}
/>
</Link>
<div className="flex w-full flex-col items-center justify-between gap-2 md:flex-row">
<div className="flex w-full flex-col items-center gap-2 min-[550px]:flex-row">
{filterSelect}
<div className="flex w-full grow items-center gap-2 md:w-auto">
{dateRangePicker}
<div className="flex grow justify-end gap-2">
<Link
href={`/${slug}/events${getQueryString({ folderId: program?.defaultFolderId, event: selectedTab, interval })}`}
>
<Button
variant="secondary"
className="w-fit"
icon={
<SquareLayoutGrid6 className="h-4 w-4 text-neutral-600" />
}
text={isMobile ? undefined : "View Events"}
/>
</Link>
</div>
</div>
</div>
</div>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "@dub/ui";
import { COUNTRIES, cn, currencyFormatter, formatDate } from "@dub/utils";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useParams, useRouter } from "next/navigation";

export default function ProgramPartnerCustomersPage() {
const { partnerId } = useParams() as { partnerId: string };
Expand All @@ -36,6 +36,7 @@ export default function ProgramPartnerCustomersPage() {
}

function PartnerCustomers({ partner }: { partner: EnrolledPartnerProps }) {
const router = useRouter();
const { slug } = useWorkspace();

const {
Expand Down Expand Up @@ -111,8 +112,17 @@ function PartnerCustomers({ partner }: { partner: EnrolledPartnerProps }) {
),
},
],
onRowClick: (row) =>
onRowClick: (row, e) => {
const url = `/${slug}/program/customers/${row.original.id}`;
if (e.metaKey || e.ctrlKey) window.open(url, "_blank");
else router.push(url);
},
onRowAuxClick: (row) =>
window.open(`/${slug}/program/customers/${row.original.id}`, "_blank"),
rowProps: (row) => ({
onPointerEnter: () =>
router.prefetch(`/${slug}/program/customers/${row.original.id}`),
}),
resourceName: (p) => `customer${p ? "s" : ""}`,
sortBy: "createdAt",
sortOrder: "desc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { cn, currencyFormatter, formatPeriod } from "@dub/utils";
import { PayoutPaidCell } from "app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useParams, useRouter } from "next/navigation";

export default function ProgramPartnerPayoutsPage() {
const { partnerId } = useParams() as { partnerId: string };
Expand All @@ -38,6 +38,7 @@ export default function ProgramPartnerPayoutsPage() {
}

function PartnerPayouts({ partner }: { partner: EnrolledPartnerProps }) {
const router = useRouter();
const { slug } = useWorkspace();

const {
Expand Down Expand Up @@ -101,12 +102,17 @@ function PartnerPayouts({ partner }: { partner: EnrolledPartnerProps }) {
},
},
],
onRowClick: (row) => {
window.open(
`/${slug}/program/payouts?partnerId=${partner.id}&payoutId=${row.original.id}&sortBy=initiatedAt`,
"_blank",
);
onRowClick: (row, e) => {
const url = `/${slug}/program/payouts/${row.original.id}`;
if (e.metaKey || e.ctrlKey) window.open(url, "_blank");
else router.push(url);
},
onRowAuxClick: (row) =>
window.open(`/${slug}/program/payouts/${row.original.id}`, "_blank"),
rowProps: (row) => ({
onPointerEnter: () =>
router.prefetch(`/${slug}/program/payouts/${row.original.id}`),
}),
resourceName: (p) => `payout${p ? "s" : ""}`,
thClassName: () => "border-l-0",
tdClassName: () => "border-l-0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import usePartnersCount from "@/lib/swr/use-partners-count";
import useProgram from "@/lib/swr/use-program";
import useWorkspace from "@/lib/swr/use-workspace";
import { EnrolledPartnerProps } from "@/lib/types";
import { ACTIVE_ENROLLMENT_STATUSES } from "@/lib/zod/schemas/partners";
import { useArchivePartnerModal } from "@/ui/modals/archive-partner-modal";
import { useBanPartnerModal } from "@/ui/modals/ban-partner-modal";
import { useBulkArchivePartnersModal } from "@/ui/modals/bulk-archive-partners-modal";
Expand All @@ -27,6 +28,7 @@ import { ProgramEnrollmentStatus } from "@dub/prisma/client";
import {
AnimatedSizeContainer,
Button,
DynamicTooltipWrapper,
EditColumnsButton,
Filter,
Icon,
Expand Down Expand Up @@ -122,7 +124,7 @@ export function PartnersTable() {
const status = (
searchParams.get("status") || searchParams.get("search")
? undefined
: "approved"
: "approved_invited"
) as ProgramEnrollmentStatus;

const sortBy =
Expand Down Expand Up @@ -529,7 +531,7 @@ export function PartnersTable() {
}}
/>

{(status === "approved" ||
{(!searchParams.get("status") ||
searchParams.get("status") === "approved") && (
<BulkActionsMenu
table={table}
Expand Down Expand Up @@ -651,6 +653,12 @@ function BulkActionsMenu({

const partnerWord = selectedPartners.length === 1 ? "partner" : "partners";

const disabledTooltip = selectedPartners.some(
(partner) => !ACTIVE_ENROLLMENT_STATUSES.includes(partner.status),
)
? `You cannot perform this action because one or more partners are not in ${ACTIVE_ENROLLMENT_STATUSES.join(", ")} statuses.`
: undefined;

return (
<Popover
openPopover={isOpen}
Expand All @@ -666,6 +674,7 @@ function BulkActionsMenu({
onArchivePartners(selectedPartners);
setIsOpen(false);
}}
disabledTooltip={disabledTooltip}
/>
<MenuItem
icon={CircleXmark}
Expand All @@ -674,6 +683,7 @@ function BulkActionsMenu({
onDeactivatePartners(selectedPartners);
setIsOpen(false);
}}
disabledTooltip={disabledTooltip}
/>
<MenuItem
icon={UserDelete}
Expand All @@ -683,6 +693,7 @@ function BulkActionsMenu({
onBanPartners(selectedPartners);
setIsOpen(false);
}}
disabledTooltip={disabledTooltip}
/>
</Command.Group>
</Command.List>
Expand Down Expand Up @@ -939,11 +950,13 @@ function MenuItem({
label,
onSelect,
variant = "default",
disabledTooltip,
}: {
icon: Icon;
label: string;
onSelect: () => void;
variant?: "default" | "danger";
disabledTooltip?: string | boolean;
}) {
const variantStyles = {
default: {
Expand All @@ -959,16 +972,22 @@ function MenuItem({
const { text, icon } = variantStyles[variant];

return (
<Command.Item
className={cn(
"flex cursor-pointer select-none items-center gap-2 whitespace-nowrap rounded-md p-2 text-sm",
"data-[selected=true]:bg-neutral-100",
text,
)}
onSelect={onSelect}
<DynamicTooltipWrapper
tooltipProps={disabledTooltip ? { content: disabledTooltip } : undefined}
>
<IconComp className={cn("size-4 shrink-0", icon)} />
{label}
</Command.Item>
<Command.Item
className={cn(
"flex cursor-pointer select-none items-center gap-2 whitespace-nowrap rounded-md p-2 text-sm",
disabledTooltip
? "cursor-not-allowed opacity-75"
: "data-[selected=true]:bg-neutral-100",
text,
)}
onSelect={disabledTooltip ? undefined : onSelect}
>
<IconComp className={cn("size-4 shrink-0", icon)} />
{label}
</Command.Item>
</DynamicTooltipWrapper>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,13 @@ function PayoutDetailsContent({
Partner: (
<ConditionalLink
href={`/${slug}/program/partners/${payout.partner.id}`}
className="flex min-w-0 items-center gap-1.5 text-neutral-500"
>
<PartnerAvatar
partner={payout.partner}
className="mr-1.5 inline-flex size-5 shrink-0"
className="mt-px size-5 shrink-0"
/>
{payout.partner.name}
<span className="truncate leading-5">{payout.partner.name}</span>
</ConditionalLink>
),

Expand Down
Loading
Loading