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

Update ReferButton to client component #1775

Merged
merged 7 commits into from
Dec 6, 2024
Merged
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
17 changes: 17 additions & 0 deletions apps/web/app/api/user/embed-tokens/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { withSession } from "@/lib/auth";
import { dub } from "@/lib/dub";
import { NextResponse } from "next/server";

export const GET = withSession(async ({ session }) => {
const referralLinkId = session.user.referralLinkId;

if (!referralLinkId) {
return NextResponse.json({ publicToken: null }, { status: 200 });
}

const { publicToken } = await dub.embedTokens.create({
linkId: referralLinkId,
});

return NextResponse.json({ publicToken });
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getSession } from "@/lib/auth/utils";
import { dub } from "@/lib/dub";
import LayoutLoader from "@/ui/layout/layout-loader";
import { AnimatedEmptyState } from "@/ui/shared/animated-empty-state";
import { DubWidget } from "@dub/embed-react";
import {
Expand All @@ -8,10 +9,18 @@ import {
InvoiceDollar,
UserCheck,
} from "@dub/ui/src/icons";
import { Suspense } from "react";

export const dynamic = "auto";

export default async function ReferralsPage() {
export default function ReferralsPage() {
return (
<Suspense fallback={<LayoutLoader />}>
<ReferralsPageRSC />
</Suspense>
);
}
async function ReferralsPageRSC() {
const session = await getSession();
const referralLinkId = session?.user.referralLinkId;

Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/app.dub.co/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MainNav } from "@/ui/layout/main-nav";
import { AppSidebarNav } from "@/ui/layout/sidebar/app-sidebar-nav";
import { HelpButtonRSC } from "@/ui/layout/sidebar/help-button-rsc";
import { NewsRSC } from "@/ui/layout/sidebar/news-rsc";
import { ReferButtonRSC } from "@/ui/layout/sidebar/refer-button-rsc";
import { ReferButton } from "@/ui/layout/sidebar/refer-button";
import Toolbar from "@/ui/layout/toolbar/toolbar";
import { constructMetadata } from "@dub/utils";
import { ReactNode } from "react";
Expand All @@ -18,7 +18,7 @@ export default async function Layout({ children }: { children: ReactNode }) {
sidebar={AppSidebarNav}
toolContent={
<>
<ReferButtonRSC />
<ReferButton />
<HelpButtonRSC />
</>
}
Expand Down
10 changes: 8 additions & 2 deletions apps/web/app/app.dub.co/embed/inline/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import useSWR from "swr";
import { Activity } from "../activity";
import { SalesList } from "../sales-list";
import { LinkToken } from "../token";
import { useIframeVisibility } from "../use-iframe-visibility";

export function EmbedInlinePageClient({
program,
Expand All @@ -33,9 +34,14 @@ export function EmbedInlinePageClient({
}) {
const [copied, copyToClipboard] = useCopyToClipboard();

const isIframeVisible = useIframeVisibility();

const { data: sales, isLoading } = useSWR<PartnerSaleResponse[]>(
"/api/embed/sales",
isIframeVisible && "/api/embed/sales",
fetcher,
{
keepPreviousData: true,
},
);

return (
Expand Down Expand Up @@ -142,7 +148,7 @@ export function EmbedInlinePageClient({
))}
</div>
</>
<LinkToken />
{isIframeVisible && <LinkToken />}
</div>
</div>
<div className="flex grow flex-col justify-end">
Expand Down
64 changes: 64 additions & 0 deletions apps/web/app/app.dub.co/embed/use-iframe-visibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useEffect, useState } from "react";

export function useIframeVisibility() {
const [isIframeVisible, setIsIframeVisible] = useState(false);

useEffect(() => {
const isInIframe = window !== window.parent;

if (isInIframe) {
setIsIframeVisible(false);

const handleVisibilityChange = () => {
const isVisible =
document.visibilityState === "visible" && !document.hidden;
setIsIframeVisible(isVisible);
};

const handleFocus = () => {
if (document.visibilityState === "visible" && !document.hidden) {
setIsIframeVisible(true);
}
};

const handleBlur = () => {
setIsIframeVisible(false);
};

document.addEventListener("visibilitychange", handleVisibilityChange);
window.addEventListener("focus", handleFocus);
window.addEventListener("blur", handleBlur);
document.addEventListener("focus", handleFocus);
document.addEventListener("blur", handleBlur);

const observer = new IntersectionObserver(
([entry]) => {
if (!entry.isIntersecting) {
setIsIframeVisible(false);
}
},
{ threshold: [0] },
);

if (window.frameElement) {
observer.observe(window.frameElement);
}

return () => {
document.removeEventListener(
"visibilitychange",
handleVisibilityChange,
);
window.removeEventListener("focus", handleFocus);
window.removeEventListener("blur", handleBlur);
document.removeEventListener("focus", handleFocus);
document.removeEventListener("blur", handleBlur);
observer.disconnect();
};
} else {
setIsIframeVisible(true);
}
}, []);

return isIframeVisible;
}
10 changes: 8 additions & 2 deletions apps/web/app/app.dub.co/embed/widget/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import useSWR from "swr";
import { Activity } from "../activity";
import { SalesList } from "../sales-list";
import { LinkToken } from "../token";
import { useIframeVisibility } from "../use-iframe-visibility";

type Tab = "invite" | "rewards";

Expand All @@ -45,9 +46,14 @@ export function EmbedWidgetPageClient({
const [copied, copyToClipboard] = useCopyToClipboard();
const [selectedTab, setSelectedTab] = useState<Tab>("invite");

const isIframeVisible = useIframeVisibility();

const { data: sales, isLoading } = useSWR<PartnerSaleResponse[]>(
"/api/embed/sales",
isIframeVisible && "/api/embed/sales",
fetcher,
{
keepPreviousData: true,
},
);

return (
Expand Down Expand Up @@ -256,7 +262,7 @@ export function EmbedWidgetPageClient({
</motion.div>
</>
)}
<LinkToken />
{isIframeVisible && <LinkToken />}
</div>
</div>
<div className="flex grow flex-col justify-end">
Expand Down
4 changes: 2 additions & 2 deletions apps/web/ui/layout/page-content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MaxWidthWrapper } from "@dub/ui";
import { cn } from "@dub/utils";
import { PropsWithChildren, ReactNode } from "react";
import { HelpButtonRSC } from "../sidebar/help-button-rsc";
import { ReferButtonRSC } from "../sidebar/refer-button-rsc";
import { ReferButton } from "../sidebar/refer-button";
import UserDropdown from "../sidebar/user-dropdown";
import { NavButton } from "./nav-button";

Expand Down Expand Up @@ -49,7 +49,7 @@ export function PageContent({
<div className="hidden md:block">{titleControls}</div>
)}
<div className="flex items-center gap-4 md:hidden">
<ReferButtonRSC />
<ReferButton />
<HelpButtonRSC />
<UserDropdown />
</div>
Expand Down
18 changes: 0 additions & 18 deletions apps/web/ui/layout/sidebar/refer-button-rsc.tsx

This file was deleted.

13 changes: 11 additions & 2 deletions apps/web/ui/layout/sidebar/refer-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@

import { DubWidget } from "@dub/embed-react";
import { Gift } from "@dub/ui/src/icons";
import { cn } from "@dub/utils";
import { cn, fetcher } from "@dub/utils";
import { AnimatePresence, motion } from "framer-motion";
import useSWRImmutable from "swr/immutable";

export function ReferButton() {
const { data: { publicToken } = {} } = useSWRImmutable<{
publicToken: string;
}>("/api/user/embed-tokens", fetcher, {
keepPreviousData: true,
});

if (!publicToken) return null;

export function ReferButton({ publicToken }: { publicToken: string }) {
return (
<DubWidget token={publicToken} options={{ trigger: "manual" }}>
<button
Expand Down
Loading