Skip to content
Open
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
44 changes: 41 additions & 3 deletions apps/web/components/document-cards/tweet-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client"

import { Suspense } from "react"
import { Suspense, useMemo } from "react"
import type { Tweet } from "react-tweet/api"
import { TweetBody, enrichTweet, TweetSkeleton } from "react-tweet"
import { cn } from "@lib/utils"
Expand Down Expand Up @@ -117,14 +117,52 @@ function CustomTweetMedia({
)
}

function isTweetLike(value: unknown): value is Tweet {
return (
typeof value === "object" &&
value !== null &&
!Array.isArray(value) &&
"user" in value
)
}

function parseTweetData(data: Tweet | string): Tweet | null {
if (!data) return null
if (typeof data !== "string") return isTweetLike(data) ? data : null
try {
const parsed: unknown = JSON.parse(data)
if (isTweetLike(parsed)) return parsed
console.warn("TweetPreview: parsed value did not match Tweet shape")
return null
} catch (error) {
console.warn("TweetPreview: failed to parse tweet data", error)
return null
}
}

function TweetPreviewFallback({ noBgColor }: { noBgColor?: boolean }) {
return (
<div
className={cn(
"w-full min-w-0 text-center text-[13px] text-[#737373]",
noBgColor ? "bg-transparent py-4" : "bg-black rounded-[18px] p-4",
dmSansClassName(),
)}
>
Tweet preview unavailable
</div>
)
}

export function TweetPreview({
data,
noBgColor,
}: {
data: Tweet
data: Tweet | string
noBgColor?: boolean
}) {
const parsedTweet = typeof data === "string" ? JSON.parse(data) : data
const parsedTweet = useMemo(() => parseTweetData(data), [data])
if (!parsedTweet) return <TweetPreviewFallback noBgColor={noBgColor} />
const tweet = enrichTweet(parsedTweet)

return (
Expand Down