Skip to content

Commit

Permalink
Add link comments to Analytics tab
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-tey committed Feb 2, 2025
1 parent 1b7db25 commit c3dccae
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 51 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
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
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 c3dccae

Please sign in to comment.