Skip to content

Commit

Permalink
Cal 🤝 Dub
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-tey committed Oct 11, 2024
1 parent 6855e1e commit e70f3b9
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 123 deletions.
2 changes: 0 additions & 2 deletions apps/web/app/api/ai/completion/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 26,6 @@ export const POST = withWorkspaceEdge(
model,
} = completionSchema.parse(await req.json());

console.log({ prompt });

const result = await streamText({
model: anthropic(model),
messages: [
Expand Down
8 changes: 4 additions & 4 deletions apps/web/app/api/cron/import/csv/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
import { addDomainToVercel, getDefaultDomains } from "@/lib/api/domains";
import { addDomainToVercel } from "@/lib/api/domains";
import { handleAndReturnErrorResponse } from "@/lib/api/errors";
import { bulkCreateLinks, createLink, processLink } from "@/lib/api/links";
import { verifyQstashSignature } from "@/lib/cron/verify-qstash";
Expand All @@ -11,6 11,7 @@ import { createLinkBodySchema } from "@/lib/zod/schemas/links";
import { randomBadgeColor } from "@/ui/links/tag-badge";
import {
DEFAULT_LINK_PROPS,
DUB_DOMAINS_ARRAY,
getPrettyUrl,
log,
parseDateTime,
Expand Down Expand Up @@ -69,7 70,7 @@ export async function POST(req: Request) {

const response = await storage.fetch(url);

const [tags, domains, defaultDomains] = await Promise.all([
const [tags, domains] = await Promise.all([
prisma.tag.findMany({
where: { projectId: workspace.id },
select: { name: true },
Expand All @@ -78,7 79,6 @@ export async function POST(req: Request) {
where: { projectId: workspace.id },
select: { slug: true },
}),
getDefaultDomains(workspace.id),
]);

const addedTags: string[] = [];
Expand Down Expand Up @@ -172,7 172,7 @@ export async function POST(req: Request) {
const domainsNotInWorkspace = selectedDomains.filter(
(domain) =>
!domains?.find((d) => d.slug === domain) &&
!defaultDomains.find((d) => d === domain) &&
!DUB_DOMAINS_ARRAY.includes(domain) &&
!addedDomains.includes(domain),
);

Expand Down
40 changes: 36 additions & 4 deletions apps/web/app/api/domains/default/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 1,3 @@
import { getDefaultDomains } from "@/lib/api/domains";
import { DubApiError } from "@/lib/api/errors";
import { withWorkspace } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
Expand All @@ -12,7 11,39 @@ export const GET = withWorkspace(
async ({ req, workspace }) => {
const searchParams = getSearchParams(req.url);
const { search } = getDefaultDomainsQuerySchema.parse(searchParams);
return NextResponse.json(await getDefaultDomains(workspace.id, { search }));

const data = await prisma.defaultDomains.findUnique({
where: {
projectId: workspace.id,
},
select: {
dubsh: true,
dublink: true,
chatgpt: true,
sptifi: true,
gitnew: true,
callink: true,
amznid: true,
ggllink: true,
figpage: true,
},
});

let defaultDomains: string[] = [];

if (data) {
defaultDomains = Object.keys(data)
.filter((key) => data[key])
.map(
(domain) =>
DUB_DOMAINS_ARRAY.find((d) => d.replace(".", "") === domain)!,
)
.filter((domain) =>
search ? domain?.toLowerCase().includes(search.toLowerCase()) : true,
);
}

return NextResponse.json(defaultDomains);
},
{
requiredPermissions: ["domains.read"],
Expand All @@ -23,8 54,8 @@ const updateDefaultDomainsSchema = z.object({
defaultDomains: z.array(z.enum(DUB_DOMAINS_ARRAY as [string, ...string[]])),
});

// PUT /api/domains/default - edit default domains
export const PUT = withWorkspace(
// PATCH /api/domains/default - edit default domains
export const PATCH = withWorkspace(
async ({ req, workspace }) => {
const { defaultDomains } = await updateDefaultDomainsSchema.parseAsync(
await req.json(),
Expand All @@ -48,6 79,7 @@ export const PUT = withWorkspace(
chatgpt: defaultDomains.includes("chatg.pt"),
sptifi: defaultDomains.includes("spti.fi"),
gitnew: defaultDomains.includes("git.new"),
callink: defaultDomains.includes("cal.link"),
amznid: defaultDomains.includes("amzn.id"),
ggllink: defaultDomains.includes("ggl.link"),
figpage: defaultDomains.includes("fig.page"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 8,7 @@ import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

// GET /api/links/verify – run keyChecks on the key
// GET /api/links/exists – run keyChecks on the key
export const GET = async (req: NextRequest) => {
try {
const searchParams = getSearchParams(req.url);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 40,7 @@ function DubDomainsIcon(domain: string) {
}

export function DefaultDomains() {
const { id, plan, role } = useWorkspace();
const { id, plan, role, flags } = useWorkspace();
const permissionsError = clientAccessCheck({
action: "domains.write",
role,
Expand Down Expand Up @@ -74,76 74,81 @@ export function DefaultDomains() {
</p>
</div>
<div className="mt-2 grid grid-cols-1 gap-3">
{DUB_DOMAINS.filter((domain) => domain.slug !== "loooooooo.ng").map(
({ slug, description }) => {
return (
<div
key={slug}
className="flex items-center justify-between gap-4 rounded-xl border border-gray-200 bg-white p-5"
>
<DomainCardTitleColumn
domain={slug}
icon={DubDomainsIcon(slug)}
description={description}
defaultDomain
/>
<Switch
disabled={submitting}
disabledTooltip={
permissionsError ||
(slug === "dub.link" && plan === "free" ? (
<TooltipContent
title="You can only use dub.link on a Pro plan and above. Upgrade to Pro to use this domain."
cta="Upgrade to Pro"
href={`/${slug}/upgrade`}
/>
) : undefined)
}
checked={defaultDomains?.includes(slug)}
fn={() => {
const oldDefaultDomains = defaultDomains.slice();
const newDefaultDomains = defaultDomains.includes(slug)
? defaultDomains.filter((d) => d !== slug)
: [...defaultDomains, slug];
{DUB_DOMAINS.filter((domain) => {
if (domain.slug === "cal.link") {
return flags?.callink;
} else if (domain.slug === "loooooooo.ng") {
return false;
}
return true;
}).map(({ slug, description }) => {
return (
<div
key={slug}
className="flex items-center justify-between gap-4 rounded-xl border border-gray-200 bg-white p-5"
>
<DomainCardTitleColumn
domain={slug}
icon={DubDomainsIcon(slug)}
description={description}
defaultDomain
/>
<Switch
disabled={submitting}
disabledTooltip={
permissionsError ||
(slug === "dub.link" && plan === "free" ? (
<TooltipContent
title="You can only use dub.link on a Pro plan and above. Upgrade to Pro to use this domain."
cta="Upgrade to Pro"
href={`/${slug}/upgrade`}
/>
) : undefined)
}
checked={defaultDomains?.includes(slug)}
fn={() => {
const oldDefaultDomains = defaultDomains.slice();
const newDefaultDomains = defaultDomains.includes(slug)
? defaultDomains.filter((d) => d !== slug)
: [...defaultDomains, slug];

setDefaultDomains(newDefaultDomains);
setSubmitting(true);
fetch(`/api/domains/default?workspaceId=${id}`, {
method: "PUT",
body: JSON.stringify({
defaultDomains: newDefaultDomains.filter(
(d) => d !== null,
),
}),
})
.then(async (res) => {
if (res.ok) {
toast.success(
`${slug} ${newDefaultDomains.includes(slug) ? "added to" : "removed from"} default domains.`,
);
await mutate();
setDefaultDomains(newDefaultDomains);
setSubmitting(true);
fetch(`/api/domains/default?workspaceId=${id}`, {
method: "PUT",
body: JSON.stringify({
defaultDomains: newDefaultDomains.filter(
(d) => d !== null,
),
}),
})
.then(async (res) => {
if (res.ok) {
toast.success(
`${slug} ${newDefaultDomains.includes(slug) ? "added to" : "removed from"} default domains.`,
);
await mutate();
} else {
const { error } = await res.json();
if (error.message.includes("Upgrade to Pro")) {
toast.custom(() => (
<UpgradeRequiredToast
title="You've discovered a Pro feature!"
message={error.message}
/>
));
} else {
const { error } = await res.json();
if (error.message.includes("Upgrade to Pro")) {
toast.custom(() => (
<UpgradeRequiredToast
title="You've discovered a Pro feature!"
message={error.message}
/>
));
} else {
toast.error(error.message);
}
setDefaultDomains(oldDefaultDomains);
toast.error(error.message);
}
})
.finally(() => setSubmitting(false));
}}
/>
</div>
);
},
)}
setDefaultDomains(oldDefaultDomains);
}
})
.finally(() => setSubmitting(false));
}}
/>
</div>
);
})}
</div>
</div>
);
Expand Down
37 changes: 0 additions & 37 deletions apps/web/lib/api/domains/get-default-domains.ts

This file was deleted.

1 change: 0 additions & 1 deletion apps/web/lib/api/domains/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 1,6 @@
export * from "./add-domain-vercel";
export * from "./delete-domain-links";
export * from "./get-config-response";
export * from "./get-default-domains";
export * from "./get-domain-response";
export * from "./remove-domain-vercel";
export * from "./utils";
Expand Down
14 changes: 13 additions & 1 deletion apps/web/lib/api/links/process-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 29,10 @@ export async function processLink<T extends Record<string, any>>({
skipExternalIdChecks = false, // only skip when externalId doesn't change (e.g. when editing a link)
}: {
payload: NewLinkProps & T;
workspace?: Pick<WorkspaceProps, "id" | "plan" | "conversionEnabled">;
workspace?: Pick<
WorkspaceProps,
"id" | "plan" | "conversionEnabled" | "flags"
>;
userId?: string;
bulk?: boolean;
skipKeyChecks?: boolean;
Expand Down Expand Up @@ -199,6 202,15 @@ export async function processLink<T extends Record<string, any>>({
};
}

if (domain === "cal.link" && !workspace?.flags?.callink) {
return {
link: payload,
error:
"You can only use the cal.link domain if you have beta access to it. Contact [email protected] to get access.",
code: "forbidden",
};
}

// else, check if the domain belongs to the workspace
} else if (!domains?.find((d) => d.slug === domain)) {
return {
Expand Down
1 change: 1 addition & 0 deletions apps/web/lib/edge-config/get-feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 17,7 @@ export const getFeatureFlags = async ({
}

const workspaceFeatures: Record<BetaFeatures, boolean> = {
callink: false,
referrals: false,
webhooks: false,
};
Expand Down
13 changes: 11 additions & 2 deletions apps/web/lib/swr/use-default-domains.ts
Original file line number Diff line number Diff line change
@@ -1,11 1,12 @@
import { fetcher } from "@dub/utils";
import { useMemo } from "react";
import useSWR from "swr";
import useWorkspace from "./use-workspace";

export default function useDefaultDomains({
search,
}: { search?: string } = {}) {
const { id } = useWorkspace();
const { id, flags } = useWorkspace();

const { data, error, mutate } = useSWR<string[]>(
id &&
Expand All @@ -19,8 20,16 @@ export default function useDefaultDomains({
},
);

const defaultDomains = useMemo(() => {
return flags && !flags.callink
? data?.filter((d) => d !== "cal.link")
: data;
}, [data, flags]);

console.log({ defaultDomains });

return {
defaultDomains: data,
defaultDomains,
loading: !data && !error,
mutate,
error,
Expand Down
Loading

0 comments on commit e70f3b9

Please sign in to comment.