chore(web): remove unused @lobbyside/react integration (#1156)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oluwabusayo Jacobs 2026-06-23 18:00:59 +01:00 committed by GitHub
parent 32a6055f7c
commit b3017eb121
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 0 additions and 329 deletions

View file

@ -1,310 +0,0 @@
"use client"
import { useCallback, useEffect, useState } from "react"
import { usePathname } from "next/navigation"
import { Phone, Users, X as XIcon } from "lucide-react"
import { useLobbyside } from "@lobbyside/react"
import { useAuth } from "@lib/auth-context"
import { cn } from "@lib/utils"
import { dmSans125ClassName } from "@/lib/fonts"
import { analytics } from "@/lib/analytics"
const STORAGE_KEY = "sm_next_app_research_cta_dismissed_v1"
const BOOK_CALL_HREF = "https://cal.com/supermemory/growth"
const LOBBYSIDE_WIDGET_ID = "e385c52f-4dd3-4fb2-81eb-da3a78059014"
function ResearchCtaHeroGraphic({
avatarUrl,
hostName,
}: {
avatarUrl?: string
hostName?: string
}) {
return (
<div
id="next-app-research-cta-hero"
className={cn(
"relative flex min-h-[4.5rem] w-full shrink-0 items-center justify-center overflow-hidden rounded-xl py-5",
"border border-white/[0.1] bg-gradient-to-b from-[#141c28] to-[#0D121A]",
)}
aria-hidden
>
<div
className="pointer-events-none absolute inset-0 opacity-[0.45]"
style={{
background:
"radial-gradient(ellipse 85% 90% at 50% 30%, rgba(59, 130, 246, 0.2), transparent 65%)",
}}
/>
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div
className="h-[120%] w-px bg-gradient-to-b from-transparent via-[#5B8DEF]/35 to-transparent"
style={{ transform: "rotate(52deg)" }}
/>
<div
className="absolute h-[120%] w-px bg-gradient-to-b from-transparent via-[#9B7AFF]/30 to-transparent"
style={{ transform: "rotate(-52deg)" }}
/>
</div>
<div className="relative z-10 flex flex-row items-center justify-center gap-10 px-3">
<div className="flex size-9 items-center justify-center">
<Phone className="size-[24px] text-[#7EB0FF]" strokeWidth={1.65} />
</div>
<span
className={cn(
dmSans125ClassName(),
"select-none text-[17px] font-light leading-none text-[#6B9FFF]/75",
)}
>
×
</span>
{avatarUrl ? (
<span className="relative inline-flex">
<img
src={avatarUrl}
alt={hostName ?? ""}
className="size-9 rounded-full object-cover ring-1 ring-[#B49CFB]/40"
/>
<span
aria-hidden
className="absolute bottom-0 right-0 size-[10px] rounded-full bg-[#22c55e] ring-2 ring-[#0D121A]"
/>
</span>
) : (
<div className="flex size-9 items-center justify-center">
<Users className="size-[24px] text-[#B49CFB]" strokeWidth={1.65} />
</div>
)}
</div>
</div>
)
}
export function NextAppResearchCta() {
const pathname = usePathname()
const [mounted, setMounted] = useState(false)
const [dismissed, setDismissed] = useState(false)
const widget = useLobbyside(LOBBYSIDE_WIDGET_ID)
const { user, org } = useAuth()
useEffect(() => {
setMounted(true)
setDismissed(localStorage.getItem(STORAGE_KEY) === "1")
}, [])
const handleDismiss = useCallback((e: React.MouseEvent) => {
e.stopPropagation()
localStorage.setItem(STORAGE_KEY, "1")
setDismissed(true)
analytics.nextAppResearchCtaDismissed()
}, [])
const handleJoinCall = useCallback(async () => {
if (widget.status !== "online" || widget.isQueueFull) return
analytics.nextAppResearchCtaLobbysideCallClicked()
// Open the tab synchronously so Safari/iOS keep the user-activation
// gesture. We redirect it once joinCall() resolves, or fall back to
// the book-a-call URL if the host goes offline / queue fills / the
// request errors between render and click.
const pendingTab = window.open("", "_blank")
const navigate = (url: string) => {
if (pendingTab && !pendingTab.closed) {
pendingTab.location.href = url
} else {
window.open(url, "_blank", "noopener,noreferrer")
}
}
try {
const visitor: Record<string, string> = {}
if (user?.email) visitor.email = user.email
if (user?.name) visitor.name = user.name
if (org?.name) visitor.company = org.name
const github = (user as { github?: unknown } | null)?.github
if (typeof github === "string" && github) visitor.github = github
const joinArgs = Object.keys(visitor).length > 0 ? { visitor } : undefined
const { entryUrl } = await widget.joinCall(joinArgs)
navigate(entryUrl)
} catch (err) {
console.error("[Lobbyside] joinCall failed", err)
navigate(BOOK_CALL_HREF)
}
}, [widget, user, org])
const handleCardKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLElement>) => {
if (e.target !== e.currentTarget) return
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
handleJoinCall()
}
},
[handleJoinCall],
)
const handleBookClick = useCallback(() => {
analytics.nextAppResearchCtaBookCallClicked()
}, [])
if (
!mounted ||
dismissed ||
pathname.startsWith("/onboarding") ||
widget.status === "loading"
) {
return null
}
const cardBaseClasses = cn(
"fixed z-[45] bottom-4 left-4 min-w-[280px] max-w-[min(calc(100vw-2rem),22.5rem)]",
"rounded-xl border border-white/[0.08] bg-[#0D121A]/95 backdrop-blur-md",
"shadow-[0_8px_32px_rgba(0,0,0,0.35)] p-3.5",
)
if (widget.status !== "online" || widget.isQueueFull) {
return (
<section
id="next-app-research-cta"
className={cardBaseClasses}
aria-label="Research participant invitation"
>
<div className="flex flex-col gap-3">
<ResearchCtaHeroGraphic />
<div className="min-w-0 w-full">
<div className="flex items-start gap-1">
<p
className={cn(
dmSans125ClassName(),
"flex-1 min-w-0 font-medium text-[12px] text-[#FAFAFA] tracking-[-0.12px]",
)}
>
Be part of the next supermemory app
</p>
<button
type="button"
onClick={handleDismiss}
className={cn(
"shrink-0 rounded-md p-1 -mr-1 -mt-0.5",
"text-muted-foreground hover:text-foreground transition-colors",
"cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring",
)}
aria-label="Dismiss"
>
<XIcon className="size-4" />
</button>
</div>
<p
className={cn(
dmSans125ClassName(),
"mt-1 text-[12px] text-[#737373] tracking-[-0.12px]",
)}
>
Share what you want next. Wed love a quick call.
</p>
<div className="mt-2.5 flex justify-end">
<a
href={BOOK_CALL_HREF}
onClick={handleBookClick}
target="_blank"
rel="noopener noreferrer"
className={cn(
dmSans125ClassName(),
"inline-flex text-[13px] font-medium text-[#A3A3A3]",
"tracking-[-0.13px] underline underline-offset-4 decoration-white/20",
"hover:text-[#FAFAFA] hover:decoration-white/40 transition-colors",
)}
>
Book a call
</a>
</div>
</div>
</div>
</section>
)
}
return (
<button
type="button"
id="next-app-research-cta"
tabIndex={0}
onClick={handleJoinCall}
onKeyDown={handleCardKeyDown}
className={cn(
cardBaseClasses,
"cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring",
)}
aria-label={`${widget.buttonText} with ${widget.hostName}`}
>
<div className="flex flex-col gap-3">
<ResearchCtaHeroGraphic
avatarUrl={widget.avatarUrl}
hostName={widget.hostName}
/>
<div className="min-w-0 w-full">
<div className="flex items-start gap-1">
<p
className={cn(
dmSans125ClassName(),
"flex-1 min-w-0 font-medium text-[12px] text-[#FAFAFA] tracking-[-0.12px]",
)}
>
{widget.ctaText}
</p>
<button
type="button"
onClick={handleDismiss}
className={cn(
"shrink-0 rounded-md p-1 -mr-1 -mt-0.5",
"text-muted-foreground hover:text-foreground transition-colors",
"cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring",
)}
aria-label="Dismiss"
>
<XIcon className="size-4" />
</button>
</div>
<div className="mt-2.5 flex items-center justify-between gap-2">
<div className="min-w-0 flex-1">
<p
className={cn(
dmSans125ClassName(),
"truncate text-[12px] font-medium text-[#FAFAFA] tracking-[-0.12px]",
)}
>
{widget.hostName}
</p>
{widget.hostTitle ? (
<p
className={cn(
dmSans125ClassName(),
"truncate text-[11px] text-[#737373] tracking-[-0.11px]",
)}
>
{widget.hostTitle}
</p>
) : null}
</div>
<button
type="button"
onClick={(e) => {
e.stopPropagation()
handleJoinCall()
}}
className={cn(
dmSans125ClassName(),
"shrink-0 inline-flex text-[13px] font-medium text-[#A3A3A3]",
"tracking-[-0.13px] underline underline-offset-4 decoration-white/20",
"hover:text-[#FAFAFA] hover:decoration-white/40 transition-colors",
"cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm",
)}
>
{widget.buttonText}
</button>
</div>
</div>
</div>
</button>
)
}

View file

@ -94,13 +94,6 @@ export const analytics = {
close_reason: "dismiss" | "close_button" | "im_good" | "action"
}) => safeCapture("integration_info_modal_closed", props),
nextAppResearchCtaDismissed: () =>
safeCapture("next_app_research_cta_dismissed"),
nextAppResearchCtaBookCallClicked: () =>
safeCapture("next_app_research_cta_book_call_clicked"),
nextAppResearchCtaLobbysideCallClicked: () =>
safeCapture("next_app_research_cta_lobbyside_call_clicked"),
mcpViewOpened: () => safeCapture("mcp_view_opened"),
mcpInstallCmdCopied: () => safeCapture("mcp_install_cmd_copied"),

View file

@ -30,7 +30,6 @@
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@floating-ui/react": "^0.27.0",
"@lobbyside/react": "0.2.0",
"@opennextjs/cloudflare": "^1.12.0",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",

View file

@ -140,7 +140,6 @@
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@floating-ui/react": "^0.27.0",
"@lobbyside/react": "0.2.0",
"@opennextjs/cloudflare": "^1.12.0",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",
@ -981,10 +980,6 @@
"@inquirer/type": ["@inquirer/type@3.0.10", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA=="],
"@instantdb/core": ["@instantdb/core@1.0.15", "", { "dependencies": { "@instantdb/version": "1.0.15", "mutative": "^1.0.10", "uuid": "^11.1.0" } }, "sha512-1A4n47U0YLHKhvl0G+CiPGfBynq1cj+NqIVRhUMc/yHYT6rePeRWesxvevNiEJU2sLxOKML6Htcbtdh7jUjSQA=="],
"@instantdb/version": ["@instantdb/version@1.0.15", "", {}, "sha512-xHDT23QK0tKAdxC2Z98mBx+znwnVShYWDsp0juY4xxzTGjrb37qNqRYb+6IIJc1J3GZ+xW/fCIexVK3b0B6fog=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@isaacs/ttlcache": ["@isaacs/ttlcache@2.1.4", "", {}, "sha512-7kMz0BJpMvgAMkyglums7B2vtrn5g0a0am77JY0GjkZZNetOBCFn7AG7gKCwT0QPiXyxW7YIQSgtARknUEOcxQ=="],
@ -1015,8 +1010,6 @@
"@levischuck/tiny-cbor": ["@levischuck/tiny-cbor@0.2.11", "", {}, "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow=="],
"@lobbyside/react": ["@lobbyside/react@0.2.0", "", { "peerDependencies": { "@instantdb/core": ">=1.0.0", "react": ">=18.0.0" } }, "sha512-24dTNDImAqZrlCu+vlPKulP1fvL3yTIc6qwxqBsqvit4z9WXnAdMRwB5Bvn31dTuaBokQEVZa3t0VfMnyhGvuw=="],
"@lukeed/csprng": ["@lukeed/csprng@1.1.0", "", {}, "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA=="],
"@lukeed/uuid": ["@lukeed/uuid@2.0.1", "", { "dependencies": { "@lukeed/csprng": "^1.1.0" } }, "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w=="],
@ -3877,8 +3870,6 @@
"multimatch": ["multimatch@6.0.0", "", { "dependencies": { "@types/minimatch": "^3.0.5", "array-differ": "^4.0.0", "array-union": "^3.0.1", "minimatch": "^3.0.4" } }, "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ=="],
"mutative": ["mutative@1.3.0", "", {}, "sha512-8MJj6URmOZAV70dpFe1YnSppRTKC4DsMkXQiBDFayLcDI4ljGokHxmpqaBQuDWa4iAxWaJJ1PS8vAmbntjjKmQ=="],
"mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="],
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
@ -5241,8 +5232,6 @@
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
"@instantdb/core/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],