Skip to content

Commit

Permalink
Merge branch 'main' into link-folders
Browse files Browse the repository at this point in the history
  • Loading branch information
devkiran committed Oct 9, 2024
2 parents c38f7f7 + 1134831 commit 3d87472
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 107 deletions.
66 changes: 35 additions & 31 deletions apps/web/app/api/workspaces/[idOrSlug]/billing/upgrade/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { APP_DOMAIN } from "@dub/utils";
import { NextResponse } from "next/server";

export const POST = withWorkspace(async ({ req, workspace, session }) => {
let { plan, period, baseUrl, comparePlans, onboarding } = await req.json();
let { plan, period, baseUrl, onboarding } = await req.json();

if (!plan || !period) {
return new Response("Invalid plan or period", { status: 400 });
Expand All @@ -16,46 +16,50 @@ export const POST = withWorkspace(async ({ req, workspace, session }) => {
lookup_keys: [`${plan}_${period}`],
});

const subscription = workspace.stripeId
? await stripe.subscriptions.list({
customer: workspace.stripeId,
status: "active",
})
const activeSubscription = workspace.stripeId
? await stripe.subscriptions
.list({
customer: workspace.stripeId,
status: "active",
})
.then((res) => res.data[0])
: null;

// if the user already has a subscription, create billing portal to upgrade
if (workspace.stripeId && subscription && subscription.data.length > 0) {
// if the user has an active subscription, create billing portal to upgrade
if (workspace.stripeId && activeSubscription) {
const { url } = await stripe.billingPortal.sessions.create({
customer: workspace.stripeId,
return_url: baseUrl,
flow_data: comparePlans
? {
type: "subscription_update",
subscription_update: {
subscription: subscription.data[0].id,
},
}
: {
type: "subscription_update_confirm",
subscription_update_confirm: {
subscription: subscription.data[0].id,
items: [
{
id: subscription.data[0].items.data[0].id,
quantity: 1,
price: prices.data[0].id,
},
],
flow_data: {
type: "subscription_update_confirm",
subscription_update_confirm: {
subscription: activeSubscription.id,
items: [
{
id: activeSubscription.items.data[0].id,
quantity: 1,
price: prices.data[0].id,
},
},
],
},
},
});

return NextResponse.json({ url });

// if the user does not have a subscription, create a new checkout session
} else {
// For both new users and users with canceled subscriptions
const stripeSession = await stripe.checkout.sessions.create({
customer_email: session.user.email,
...(workspace.stripeId
? {
customer: workspace.stripeId,
// need to pass this or Stripe will throw an error: https://git.new/kX4fi6B
customer_update: {
name: "auto",
address: "auto",
},
}
: {
customer_email: session.user.email,
}),
billing_address_collection: "required",
success_url: `${APP_DOMAIN}/${workspace.slug}?${onboarding ? "onboarded" : "upgraded"}=true&plan=${plan}&period=${period}`,
cancel_url: baseUrl,
Expand Down
6 changes: 3 additions & 3 deletions apps/web/app/app.dub.co/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ChangelogPopup from "@/ui/layout/changelog-popup";
import { MainNav } from "@/ui/layout/main-nav";
import NavTabs from "@/ui/layout/nav-tabs";
import Toolbar from "@/ui/layout/toolbar/toolbar";
import UserSurveyPopup from "@/ui/layout/user-survey";
import { MaxWidthWrapper } from "@dub/ui";
import { constructMetadata } from "@dub/utils";
import { ReactNode, Suspense } from "react";
Expand All @@ -24,8 +24,8 @@ export default function Layout({ children }: { children: ReactNode }) {
</div>
{children}
</div>
{/* <UserSurveyPopup /> */}
<ChangelogPopup />
<UserSurveyPopup />
{/* <ChangelogPopup /> */}
<Toolbar />
</Providers>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/lib/tinybird/record-click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export async function recordClick({
typeof ip === "string" && ip.trim().length > 0 && !isEuCountry ? ip : "",
continent: continent || "",
country: geo.country || "Unknown",
city: geo.city ? decodeURIComponent(geo.city) : "Unknown",
city: geo.city || "Unknown",
region: geo.region || "Unknown",
latitude: geo.latitude || "Unknown",
longitude: geo.longitude || "Unknown",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@upstash/ratelimit": "^1.1.3",
"@upstash/redis": "^1.25.1",
"@vercel/edge-config": "^0.4.1",
"@vercel/functions": "^1.4.1",
"@vercel/functions": "^1.4.2",
"@vercel/og": "^0.6.3",
"@visx/axis": "^2.14.0",
"@visx/curve": "^3.3.0",
Expand Down
51 changes: 51 additions & 0 deletions apps/web/ui/modals/link-builder/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { LinkWithTagsProps } from "@/lib/types";
import {
CircleHalfDottedClock,
Crosshairs3,
Flag6,
Gift,
GlobePointer,
Incognito,
InputPassword,
InputSearch,
Page2,
SatelliteDish,
SquareChart,
WindowSearch,
} from "@dub/ui/src/icons";
Expand Down Expand Up @@ -99,3 +105,48 @@ export const MOBILE_MORE_ITEMS = [
type: "modal",
},
];

export const UTM_PARAMETERS = [
{
key: "utm_source",
icon: GlobePointer,
label: "Source",
placeholder: "google",
description: "Where the traffic is coming from",
},
{
key: "utm_medium",
icon: SatelliteDish,
label: "Medium",
placeholder: "cpc",
description: "How the traffic is coming",
},
{
key: "utm_campaign",
icon: Flag6,
label: "Campaign",
placeholder: "summer_sale",
description: "The name of the campaign",
},
{
key: "utm_term",
icon: InputSearch,
label: "Term",
placeholder: "running shoes",
description: "The term of the campaign",
},
{
key: "utm_content",
icon: Page2,
label: "Content",
placeholder: "logolink",
description: "The content of the campaign",
},
{
key: "ref",
icon: Gift,
label: "Referral",
placeholder: "yoursite.com",
description: "The referral of the campaign",
},
] as const;
73 changes: 69 additions & 4 deletions apps/web/ui/modals/link-builder/targeting-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import {
useKeyboardShortcut,
} from "@dub/ui";
import { Crosshairs3, Trash } from "@dub/ui/src/icons";
import { cn, COUNTRIES } from "@dub/utils";
import {
cn,
constructURLFromUTMParams,
COUNTRIES,
getParamsFromURL,
isValidUrl,
} from "@dub/utils";
import {
Dispatch,
Fragment,
Expand All @@ -20,6 +26,7 @@ import {
} from "react";
import { useForm, useFormContext } from "react-hook-form";
import { LinkFormData } from ".";
import { UTM_PARAMETERS } from "./constants";

function TargetingModal({
showTargetingModal,
Expand Down Expand Up @@ -63,6 +70,24 @@ function TargetingModal({
iosParent || androidParent || Object.keys(geoParent || {}).length > 0,
);

// Get UTM parameters from the parent URL that need to be added on blur
const getNewParams = useCallback(
(targetURL: string) => {
if (!targetURL?.trim() || !isValidUrl(targetURL)) return;

const parentUrl = getValuesParent("url");
const parentParams = getParamsFromURL(parentUrl);
const targetParams = getParamsFromURL(targetURL);

const newParams = UTM_PARAMETERS.filter(
({ key }) => parentParams?.[key] && !targetParams?.[key],
).map(({ key }) => [key, parentParams[key]]);

return newParams.length ? Object.fromEntries(newParams) : null;
},
[getValuesParent],
);

return (
<>
<Modal
Expand Down Expand Up @@ -136,7 +161,9 @@ function TargetingModal({
<Fragment key={key}>
<div className="z-[1]">
<Combobox
selected={{ value: key, label: COUNTRIES[key] }}
selected={
key ? { value: key, label: COUNTRIES[key] } : null
}
setSelected={(option) => {
if (!option) return;
const newGeo = {};
Expand Down Expand Up @@ -200,6 +227,22 @@ function TargetingModal({
{ shouldDirty: true },
);
}}
onBlur={(e) => {
const newParams = getNewParams(e.target.value);

if (newParams)
setValue(
`geo`,
{
...((geo as object) || {}),
[key]: constructURLFromUTMParams(
value,
newParams,
),
},
{ shouldDirty: true },
);
}}
/>
<div className="pl-1.5">
<Button
Expand Down Expand Up @@ -258,7 +301,18 @@ function TargetingModal({
id={`${id}-ios-url`}
placeholder="https://apps.apple.com/app/1611158928"
className="block w-full rounded-md border-gray-300 text-gray-900 placeholder-gray-400 focus:border-gray-500 focus:outline-none focus:ring-gray-500 sm:text-sm"
{...register("ios")}
{...register("ios", {
onBlur: (e) => {
const newParams = getNewParams(e.target.value);

if (newParams)
setValue(
"ios",
constructURLFromUTMParams(e.target.value, newParams),
{ shouldDirty: true },
);
},
})}
/>
</div>
</div>
Expand Down Expand Up @@ -287,7 +341,18 @@ function TargetingModal({
id={`${id}-android-url`}
placeholder="https://play.google.com/store/apps/details?id=com.disney.disneyplus"
className="block w-full rounded-md border-gray-300 text-gray-900 placeholder-gray-400 focus:border-gray-500 focus:outline-none focus:ring-gray-500 sm:text-sm"
{...register("android")}
{...register("android", {
onBlur: (e) => {
const newParams = getNewParams(e.target.value);

if (newParams)
setValue(
"android",
constructURLFromUTMParams(e.target.value, newParams),
{ shouldDirty: true },
);
},
})}
/>
</div>
</div>
Expand Down
Loading

0 comments on commit 3d87472

Please sign in to comment.