Skip to content

Commit

Permalink
Merge pull request #1964 from dubinc/analytics-link-comments
Browse files Browse the repository at this point in the history
Add link comments to Analytics tab
  • Loading branch information
steven-tey authored Feb 3, 2025
2 parents 7c86c69 + 58df326 commit 98c1d23
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IntegrationLogo } from "@/ui/integrations/integration-logo";
import { useUninstallIntegrationModal } from "@/ui/modals/uninstall-integration-modal";
import { BackLink } from "@/ui/shared/back-link";
import { ThreeDots } from "@/ui/shared/icons";
import { Markdown } from "@/ui/shared/markdown";
import {
Avatar,
BlurImage,
Expand Down Expand Up @@ -45,7 +46,6 @@ import {
import { useAction } from "next-safe-action/hooks";
import Link from "next/link";
import { useState } from "react";
import Markdown from "react-markdown";
import { toast } from "sonner";

const integrationSettings = {
Expand Down Expand Up @@ -290,22 +290,7 @@ export default function IntegrationPageClient({
</Carousel>
) : null}

{integration.readme && (
<Markdown
className={cn(
"prose prose-sm prose-gray max-w-none p-6 transition-all",
"prose-headings:leading-tight",
"prose-a:font-medium prose-a:text-neutral-500 prose-a:underline-offset-4 hover:prose-a:text-black",
)}
components={{
a: ({ node, ...props }) => (
<a {...props} target="_blank" rel="noopener noreferrer" />
),
}}
>
{integration.readme}
</Markdown>
)}
{integration.readme && <Markdown>{integration.readme}</Markdown>}
</div>

{SettingsComponent && <SettingsComponent {...integration} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Suspense } from "react";
import DashboardPasswordForm from "./form";

export const dynamic = "force-dynamic";
export const runtime = "edge";

export async function generateMetadata({
params,
Expand Down
2 changes: 2 additions & 0 deletions apps/web/lib/analytics/get-analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export const getAnalytics = async (params: AnalyticsFilters) => {
domain: true,
key: true,
url: true,
comments: true,
createdAt: true,
},
});
Expand All @@ -148,6 +149,7 @@ export const getAnalytics = async (params: AnalyticsFilters) => {
domain: link.domain,
key: punyEncode(link.key),
}),
comments: link.comments,
createdAt: link.createdAt.toISOString(),
...topLink,
});
Expand Down
4 changes: 2 additions & 2 deletions apps/web/lib/fetchers/get-dashboard.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { prismaEdge } from "@dub/prisma/edge";
import { prisma } from "@dub/prisma";
import { cache } from "react";

export const getDashboard = cache(async ({ id }: { id: string }) => {
return await prismaEdge.dashboard.findUnique({
return await prisma.dashboard.findUnique({
where: {
id,
},
Expand Down
1 change: 1 addition & 0 deletions apps/web/lib/zod/schemas/analytics-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ export const analyticsResponse = {
key: z.string().describe("The key of the short link"),
shortLink: z.string().describe("The short link URL"),
url: z.string().describe("The destination URL of the short link"),
comments: z.string().nullish().describe("The comments of the short link"),
createdAt: z
.string()
.describe("The creation timestamp of the short link"),
Expand Down
4 changes: 3 additions & 1 deletion apps/web/ui/analytics/link-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { LinkProps } from "@/lib/types";
import { CopyButton, LinkLogo } from "@dub/ui";
import { ArrowTurnRight2 } from "@dub/ui/icons";
import { getApexDomain, getPrettyUrl, linkConstructor } from "@dub/utils";
import { CommentsBadge } from "../links/comments-badge";

export default function LinkPreviewTooltip({ data }: { data: LinkProps }) {
const { domain, key, url } = data;
const { domain, key, url, comments } = data;

return (
<div className="relative flex w-[28rem] items-center gap-x-2 px-4 py-2">
Expand Down Expand Up @@ -35,6 +36,7 @@ export default function LinkPreviewTooltip({ data }: { data: LinkProps }) {
variant="neutral"
className="p-1.5"
/>
{comments && <CommentsBadge comments={comments} />}
</div>
</div>
<div className="flex min-w-0 items-center gap-1 text-sm">
Expand Down
2 changes: 1 addition & 1 deletion apps/web/ui/analytics/top-links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function TopLinks() {
const dataKey = selectedTab === "sales" ? saleUnit : "count";

const [tab, setTab] = useState<"links" | "urls">("links");
const { data, loading } = useAnalyticsFilterOption({
const { data } = useAnalyticsFilterOption({
groupBy: `top_${tab}`,
});

Expand Down
36 changes: 36 additions & 0 deletions apps/web/ui/links/comments-badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { Markdown } from "@/ui/shared/markdown";
import { Page2 } from "@dub/ui/icons";
import * as HoverCard from "@radix-ui/react-hover-card";

export function CommentsBadge({ comments }: { comments: string }) {
return (
<div className="hidden sm:block">
<HoverCard.Root openDelay={100}>
<HoverCard.Portal>
<HoverCard.Content
side="bottom"
sideOffset={8}
className="animate-slide-up-fade z-[99] items-center overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm"
>
<div className="divide-y-gray-200 divide-y text-sm">
<div className="flex items-center gap-2 px-4 py-3">
<Page2 className="size-3.5" />
<span className="text-gray-500">Link comments</span>
</div>
<Markdown className="max-w-[300px] whitespace-normal break-words px-5 py-3">
{comments}
</Markdown>
</div>
</HoverCard.Content>
</HoverCard.Portal>
<HoverCard.Trigger asChild>
<div className="rounded-full p-1.5 hover:bg-gray-100">
<Page2 className="size-3.5" />
</div>
</HoverCard.Trigger>
</HoverCard.Root>
</div>
);
}
33 changes: 1 addition & 32 deletions apps/web/ui/links/link-title-column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
EarthPosition,
Incognito,
InputPassword,
Page2,
Robot,
SquareChart,
} from "@dub/ui/icons";
Expand All @@ -39,6 +38,7 @@ import * as HoverCard from "@radix-ui/react-hover-card";
import { Mail } from "lucide-react";
import { memo, PropsWithChildren, useContext, useRef, useState } from "react";
import { useLinkBuilder } from "../modals/link-builder";
import { CommentsBadge } from "./comments-badge";
import { ResponseLink } from "./links-container";
import { LinksDisplayContext } from "./links-display-provider";

Expand Down Expand Up @@ -231,37 +231,6 @@ function SettingsBadge({ link }: { link: ResponseLink }) {
);
}

function CommentsBadge({ comments }: { comments: string }) {
return (
<div className="hidden sm:block">
<HoverCard.Root openDelay={100}>
<HoverCard.Portal>
<HoverCard.Content
side="bottom"
sideOffset={8}
className="animate-slide-up-fade z-[99] items-center overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm"
>
<div className="divide-y-gray-200 divide-y text-sm">
<div className="flex items-center gap-2 px-4 py-3">
<Page2 className="size-3.5" />
<span className="text-gray-500">Link comments</span>
</div>
<p className="max-w-[300px] px-5 py-3 text-gray-700">
{comments}
</p>
</div>
</HoverCard.Content>
</HoverCard.Portal>
<HoverCard.Trigger asChild>
<div className="rounded-full p-1.5 hover:bg-gray-100">
<Page2 className="size-3.5" />
</div>
</HoverCard.Trigger>
</HoverCard.Root>
</div>
);
}

const Details = memo(
({ link, compact }: { link: ResponseLink; compact?: boolean }) => {
const { url, createdAt } = link;
Expand Down
35 changes: 35 additions & 0 deletions apps/web/ui/shared/markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use client";

import { cn } from "@dub/utils";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

export function Markdown({
children,
className,
components,
}: {
children: string;
className?: string;
components?: any;
}) {
return (
<ReactMarkdown
className={cn(
"prose prose-sm prose-gray max-w-none p-6 transition-all",
"prose-headings:leading-tight",
"prose-a:font-medium prose-a:text-neutral-500 prose-a:underline-offset-4 hover:prose-a:text-black",
className,
)}
components={{
a: ({ node, ...props }) => (
<a {...props} target="_blank" rel="noopener noreferrer" />
),
...components,
}}
remarkPlugins={[remarkGfm] as any}
>
{children}
</ReactMarkdown>
);
}

0 comments on commit 98c1d23

Please sign in to comment.