Skip to content

Commit

Permalink
Merge branch 'main' into harshbhat/supportSidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
harshsbhat authored Sep 21, 2024
2 parents ba3e055 + 2cf7e94 commit 56467f6
Show file tree
Hide file tree
Showing 7 changed files with 472 additions and 402 deletions.
1 change: 0 additions & 1 deletion apps/agent/services/ratelimit/ratelimit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ func TestAccuracy_fixed_time(t *testing.T) {

require.GreaterOrEqual(t, passed, lower)
require.LessOrEqual(t, passed, int64(float64(limit*(windows+1))*upper))

})
}

Expand Down
23 changes: 13 additions & 10 deletions apps/dashboard/app/(app)/settings/billing/plans/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ export const ChangePlanButton: React.FC<Props> = ({ workspace, newPlan, label })
},
});

const handleClick = () => {
const hasPaymentMethod = !!workspace.stripeCustomerId;
if (!hasPaymentMethod && newPlan === "pro") {
return router.push(`/settings/billing/stripe?new_plan=${newPlan}`);
}

changePlan.mutateAsync({
workspaceId: workspace.id,
plan: newPlan === "free" ? "free" : "pro",
});
};

const isSamePlan = workspace.plan === newPlan;
return (
<Dialog open={open} onOpenChange={setOpen}>
Expand Down Expand Up @@ -90,16 +102,7 @@ export const ChangePlanButton: React.FC<Props> = ({ workspace, newPlan, label })
<Button className="col-span-1" variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button
className="col-span-1"
variant="primary"
onClick={() =>
changePlan.mutateAsync({
workspaceId: workspace.id,
plan: newPlan === "free" ? "free" : "pro",
})
}
>
<Button className="col-span-1" variant="primary" onClick={handleClick}>
{changePlan.isLoading ? <Loading /> : "Switch"}
</Button>
</DialogFooter>
Expand Down
16 changes: 14 additions & 2 deletions apps/dashboard/app/(app)/settings/billing/stripe/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ import { headers } from "next/headers";
import { redirect } from "next/navigation";
import Stripe from "stripe";

export default async function StripeRedirect() {
type Props = {
searchParams: {
new_plan: "free" | "pro" | undefined;
};
};

export default async function StripeRedirect(props: Props) {
const { new_plan } = props.searchParams;
const tenantId = getTenantId();
if (!tenantId) {
return redirect("/auth/sign-in");
Expand Down Expand Up @@ -53,7 +60,12 @@ export default async function StripeRedirect() {
const baseUrl = process.env.VERCEL_URL ? "https://app.unkey.com" : "http://localhost:3000";

// do not use `new URL(...).searchParams` here, because it will escape the curly braces and stripe will not replace them with the session id
const successUrl = `${baseUrl}/settings/billing/stripe/success?session_id={CHECKOUT_SESSION_ID}`;
let successUrl = `${baseUrl}/settings/billing/stripe/success?session_id={CHECKOUT_SESSION_ID}`;

// if they're coming from the change plan flow, pass along the new plan param
if (new_plan && new_plan !== ws.plan) {
successUrl += `&new_plan=${new_plan}`;
}

const cancelUrl = headers().get("referer") ?? baseUrl;
const session = await stripe.checkout.sessions.create({
Expand Down
20 changes: 17 additions & 3 deletions apps/dashboard/app/(app)/settings/billing/stripe/success/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import { Code } from "@/components/ui/code";
import { getTenantId } from "@/lib/auth";
import { db, eq, schema } from "@/lib/db";
import { stripeEnv } from "@/lib/env";
import { PostHogClient } from "@/lib/posthog";
import { currentUser } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import Stripe from "stripe";

type Props = {
searchParams: {
session_id: string;
new_plan: "free" | "pro" | undefined;
};
};

export default async function StripeSuccess(props: Props) {
const { session_id, new_plan } = props.searchParams;
const tenantId = getTenantId();
if (!tenantId) {
return redirect("/auth/sign-in");
Expand Down Expand Up @@ -44,14 +47,14 @@ export default async function StripeSuccess(props: Props) {
typescript: true,
});

const session = await stripe.checkout.sessions.retrieve(props.searchParams.session_id);
const session = await stripe.checkout.sessions.retrieve(session_id);
if (!session) {
return (
<EmptyPlaceholder>
<EmptyPlaceholder.Title>Stripe session not found</EmptyPlaceholder.Title>
<EmptyPlaceholder.Description>
The Stripe session <Code>{props.searchParams.session_id}</Code> you are trying to access
does not exist. Please contact [email protected].
The Stripe session <Code>{session_id}</Code> you are trying to access does not exist.
Please contact [email protected].
</EmptyPlaceholder.Description>
</EmptyPlaceholder>
);
Expand All @@ -69,14 +72,25 @@ export default async function StripeSuccess(props: Props) {
);
}

const isChangingPlan = new_plan && new_plan !== ws.plan;

await db
.update(schema.workspaces)
.set({
stripeCustomerId: customer.id,
stripeSubscriptionId: session.subscription as string,
trialEnds: null,
...(isChangingPlan ? { plan: new_plan } : {}),
})
.where(eq(schema.workspaces.id, ws.id));

if (isChangingPlan) {
PostHogClient.capture({
distinctId: tenantId,
event: "plan_changed",
properties: { plan: new_plan, workspace: ws.id },
});
}

return redirect("/settings/billing");
}
29 changes: 29 additions & 0 deletions apps/dashboard/lib/posthog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { PostHog } from "posthog-node";

class PostHogClientWrapper {
private static instance: PostHog | null = null;

private constructor() {}

public static getInstance(): PostHog {
if (!PostHogClientWrapper.instance) {
if (!process.env.NEXT_PUBLIC_POSTHOG_KEY || !process.env.NEXT_PUBLIC_POSTHOG_HOST) {
console.warn("PostHog key is missing. Analytics data will not be sent.");
// Return a mock client when the key is not present
PostHogClientWrapper.instance = {
capture: () => {},
// Add other methods from PostHog, implementing them as no-ops
} as unknown as PostHog;
} else {
PostHogClientWrapper.instance = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
flushAt: 1,
flushInterval: 0,
});
}
}
return PostHogClientWrapper.instance;
}
}

export const PostHogClient = PostHogClientWrapper.getInstance();
1 change: 1 addition & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"postcss": "8.4.38",
"postcss-focus-visible": "^9.0.1",
"posthog-js": "^1.130.1",
"posthog-node": "^4.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.3",
Expand Down
Loading

0 comments on commit 56467f6

Please sign in to comment.