import * as ReactTweet from "react-tweet"; import { ReactNode, memo, useCallback, useEffect, useMemo, useState } from "react"; import { EnrichedTweet, TwitterComponents } from "react-tweet"; import type { Tweet } from "react-tweet/api"; import "react-tweet/theme.css"; import { QuotedTweet } from "./quoted-tweet/quoted-tweet"; import tweetBodyStyles from "./tweet-body.module.css"; import tweetContainerStyles from "./tweet-container.module.css"; import tweetHeaderStyles from "./tweet-header.module.css"; import tweetInReplyToStyles from "./tweet-in-reply-to.module.css"; import tweetLinkStyles from "./tweet-link.module.css"; import { TweetMedia } from "./tweet-media"; import { VerifiedBadge } from "./verified-badge"; import clsx from "clsx"; import { useTheme } from "~/lib/theme-provider"; const { enrichTweet } = ReactTweet; type Props = { tweet: Tweet | { error: string }; components?: TwitterComponents; }; type AvatarImgProps = { src: string; alt: string; width: number; height: number; }; const AvatarImg = memo((props: AvatarImgProps) => ); const TweetHeader = memo( ({ tweet, components }: { tweet: EnrichedTweet; components?: TwitterComponents }) => { const Img = components?.AvatarImg ?? AvatarImg; const { user } = tweet; const avatarClasses = useMemo( () => clsx( tweetHeaderStyles.avatarOverflow, user.profile_image_shape === "Square" && tweetHeaderStyles.avatarSquare, ), [user.profile_image_shape], ); return (
{user.name}
{user.name}
@{user.screen_name}
); }, ); export const TweetContainer = memo( ({ className, children }: { className?: string; children: ReactNode }) => { const containerClasses = useMemo( () => clsx("react-tweet-theme", tweetContainerStyles.root, className), [className], ); return (
{children}
); }, ); export const TweetInReplyTo = memo(({ tweet }: { tweet: EnrichedTweet }) => ( Replying to @{tweet.in_reply_to_screen_name} )); export const TweetBody = memo(({ tweet }: { tweet: EnrichedTweet }) => { const renderEntity = useCallback((item: any, i: number) => { switch (item.type) { case "hashtag": case "mention": case "url": case "symbol": return ( {item.text} ); case "media": return; default: return ; } }, []); return (

{tweet.entities.map(renderEntity)}

); }); export const TweetLink = memo(({ href, children }: { children: ReactNode; href: string }) => ( {children} )); export const CustomTwitterComp = memo(({ tweet: t, components }: Props) => { const [tweet, setTweet] = useState(null); const [theme] = useTheme(); useEffect(() => { console.log("t", t); if ("error" in t) { setTweet(null); } else { try { const enrichedTweet = enrichTweet(t); setTweet(enrichedTweet); } catch (error) { console.error("Failed to enrich tweet:", error); setTweet(null); } } }, [t]); const tweetId = useMemo( () => (tweet && typeof tweet === "object" ? `tweet-${tweet?.id_str}-${theme}` : ""), [tweet?.id_str, theme], ); if (typeof tweet === "undefined" || tweet === null) { return ; } if ("error" in t) { return
{"Failed to load tweet"}
; } return (
{tweet.in_reply_to_status_id_str && } {tweet.mediaDetails?.length ? : null} {tweet.quoted_tweet && }
); });