Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support regions in Segment integration #1897

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
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
13 changes: 11 additions & 2 deletions apps/web/lib/integrations/segment/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,39 @@ import { SEGMENT_INTEGRATION_ID } from "@dub/utils";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { installIntegration } from "../install";
import { segmentRegions } from "./utils";

const schema = z.object({
writeKey: z.string().min(1).max(40),
region: z.enum(segmentRegions.map((r) => r.value) as [string, ...string[]]),
workspaceId: z.string(),
});

export const installSegmentAction = authActionClient
.schema(schema)
.action(async ({ parsedInput, ctx }) => {
const { workspace, user } = ctx;
const { writeKey } = parsedInput;
const { writeKey, region } = parsedInput;

const installation = await installIntegration({
integrationId: SEGMENT_INTEGRATION_ID,
userId: user.id,
workspaceId: workspace.id,
credentials: {
writeKey,
region,
},
});

const url = segmentRegions.find((r) => r.value === region)?.url;

if (!url) {
throw new Error("Invalid region.");
}

await createWebhook({
name: "Segment",
url: "https://api.segment.io/v1/track",
url,
receiver: WebhookReceiver.segment,
triggers: [],
workspace,
Expand Down
108 changes: 76 additions & 32 deletions apps/web/lib/integrations/segment/ui/set-write-key.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"use client";

import useWorkspace from "@/lib/swr/use-workspace";
import { SegmentIntegrationCredentials } from "@/lib/types";
import { SegmentIntegrationCredentials, SegmentRegion } from "@/lib/types";
import { Lock } from "@/ui/shared/icons";
import { Button, Tooltip, TooltipContent } from "@dub/ui";
import { Button, InfoTooltip, Tooltip, TooltipContent } from "@dub/ui";
import { cn } from "@dub/utils";
import { useAction } from "next-safe-action/hooks";
import { useState } from "react";
import { toast } from "sonner";
import { installSegmentAction } from "../install";
import { segmentRegions } from "../utils";

export function SetWriteKey({
credentials,
Expand All @@ -18,6 +20,7 @@ export function SetWriteKey({
}) {
const { id: workspaceId, slug, plan } = useWorkspace();
const [writeKey, setWriteKey] = useState(credentials?.writeKey);
const [region, setRegion] = useState(credentials?.region || "us-west-2");

const { executeAsync, isPending } = useAction(installSegmentAction, {
async onSuccess() {
Expand All @@ -43,6 +46,7 @@ export function SetWriteKey({
await executeAsync({
workspaceId,
writeKey,
region,
});
};

Expand All @@ -54,18 +58,82 @@ export function SetWriteKey({
/>
);

const canInstall = !["free", "pro"].includes(plan || "");

return (
<form className="mt-4 flex items-end gap-2" onSubmit={onSubmit}>
<div className="w-full rounded-lg border border-gray-200 bg-white">
<div className="flex items-center gap-x-2 border-b border-gray-200 px-6 py-4">
<Lock className="size-4" />
<p className="text-sm font-medium text-gray-700">Write key</p>
<p className="text-sm font-medium text-gray-700">Configure Segment</p>
</div>

<div className="space-y-4 p-4">
<div>
<label htmlFor="writeKey" className="flex items-center space-x-2">
<h2 className="text-sm font-medium text-gray-900">Write key</h2>
<InfoTooltip content="The write key is used to send events to Segment." />
</label>

{!canInstall ? (
<Tooltip content={planDisabledTooltip}>
<div className="mt-1 cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-sm text-gray-400">
Enter your write key
</div>
</Tooltip>
) : (
<div className="relative mt-1 rounded-md shadow-sm">
<input
className={cn(
"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",
{
"cursor-not-allowed bg-gray-50": !canInstall,
},
)}
placeholder="Enter your write key"
required
type="text"
autoComplete="off"
name="writeKey"
value={writeKey}
onChange={(e) => setWriteKey(e.target.value)}
readOnly={installed}
/>
</div>
)}
</div>

<div>
<label htmlFor="region" className="flex items-center space-x-2">
<h2 className="text-sm font-medium text-gray-900">
Select the region
</h2>
<InfoTooltip content="Choose the data region where your events will be sent." />
</label>

<div className="mt-2 space-y-2">
{segmentRegions.map(({ name, value }) => (
<div key={value} className="flex items-center">
<input
type="radio"
name="region"
value={value}
checked={region === value}
onChange={() => setRegion(value as SegmentRegion)}
className="h-4 w-4 cursor-pointer rounded-full border-gray-300 text-black focus:outline-none focus:ring-0"
disabled={!canInstall || installed}
/>
<label htmlFor={value} className="ml-2 text-sm text-gray-700">
{name}
</label>
</div>
))}
</div>
</div>
</div>

<div className="p-4">
<p className="text-sm leading-normal text-gray-600">
To send click events to Segment, you need to add your Segment write
key below.{" "}
<div className="flex items-center justify-between rounded-b-lg border-t border-gray-200 bg-gray-50 px-4 py-3">
<p className="text-sm text-gray-500">
<a
href="https://segment.com/docs/connections/find-writekey/"
target="_blank"
Expand All @@ -74,33 +142,9 @@ export function SetWriteKey({
>
Learn about
</a>{" "}
how to locate your write key.
how to locate your write key on Segment.
</p>

{plan === "free" || plan === "pro" ? (
<Tooltip content={planDisabledTooltip}>
<div className="mt-4 cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-sm text-gray-400">
Enter your write key
</div>
</Tooltip>
) : (
<div className="relative mt-4 rounded-md shadow-sm">
<input
className="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"
placeholder="Enter your write key"
required
type="text"
autoComplete="off"
name="writeKey"
value={writeKey}
onChange={(e) => setWriteKey(e.target.value)}
readOnly={installed}
/>
</div>
)}
</div>

<div className="flex items-center justify-end rounded-b-lg border-t border-gray-200 bg-gray-50 px-4 py-3">
<div className="shrink-0">
<Button
type="submit"
Expand Down
13 changes: 13 additions & 0 deletions apps/web/lib/integrations/segment/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
export const createSegmentBasicAuthHeader = (writeKey: string) => {
return `Basic ${Buffer.from(`${writeKey}:`).toString("base64")}`;
};

export const segmentRegions = [
{
name: "Oregon (US Default)",
value: "us-west-2",
url: "https://api.segment.io/v1/track",
},
{
name: "Dublin",
value: "eu-west-1",
url: "https://events.eu1.segmentapis.com/v1/track",
},
];
5 changes: 5 additions & 0 deletions apps/web/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Webhook,
YearInReview,
} from "@dub/prisma/client";
import { segmentRegions } from "./integrations/segment/utils";
import { WEBHOOK_TRIGGER_DESCRIPTIONS } from "./webhook/constants";
import { clickEventResponseSchema } from "./zod/schemas/clicks";
import {
Expand Down Expand Up @@ -379,9 +380,13 @@ export type PayoutResponse = z.infer<typeof PayoutResponseSchema>;

export type PartnerPayoutResponse = z.infer<typeof PartnerPayoutResponseSchema>;

export type SegmentRegion = (typeof segmentRegions)[number]["value"];

export type SegmentIntegrationCredentials = {
writeKey?: string;
region?: SegmentRegion;
};

export type InvoiceProps = z.infer<typeof InvoiceSchema>;

export type CustomerActivity = z.infer<typeof customerActivitySchema>;
Expand Down
Loading