diff --git a/src/components/captcha/CaptchaInvisible.tsx b/src/components/captcha/CaptchaInvisible.tsx index 14ba37c16..37d94f28e 100644 --- a/src/components/captcha/CaptchaInvisible.tsx +++ b/src/components/captcha/CaptchaInvisible.tsx @@ -1,5 +1,6 @@ import { getCaptchaSiteKey } from '@/utils/env/client' import React, { useRef } from 'react' +import { createPortal } from 'react-dom' import ReCAPTCHA from 'react-google-recaptcha' import { toast } from 'react-hot-toast' import Toast from '../Toast' @@ -38,13 +39,16 @@ export default function CaptchaInvisible({ children }: CaptchaInvisibleProps) { {children(runCaptcha, (className) => ( ))} - + {createPortal( + , + document.body + )} ) } diff --git a/src/components/chats/ChatItem/Embed.module.css b/src/components/chats/ChatItem/Embed.module.css index 4ef1049e8..b60261e92 100644 --- a/src/components/chats/ChatItem/Embed.module.css +++ b/src/components/chats/ChatItem/Embed.module.css @@ -1,3 +1,4 @@ .Embed :global(.react-tweet-theme) { --tweet-body-font-size: 1rem; + min-width: auto; } diff --git a/src/components/chats/ChatItem/Embed.tsx b/src/components/chats/ChatItem/Embed.tsx index 214469dd3..80707b980 100644 --- a/src/components/chats/ChatItem/Embed.tsx +++ b/src/components/chats/ChatItem/Embed.tsx @@ -17,7 +17,7 @@ export default function Embed({ link: url, ...props }: EmbedProps) { return ( Component && ( -
+
) @@ -55,7 +55,8 @@ const urlMapper: { ) }, checker: (link: string) => - /(?:https?:\/\/)?(?:www\.)?(?:twitter\.com)\/(.+)/.test(link), + /(?:https?:\/\/)?(?:www\.)?(?:twitter\.com)\/(.+)/.test(link) && + /\/status\/\d+/.test(link), }, { name: 'tiktok', diff --git a/src/components/chats/ChatItem/LinkPreview.tsx b/src/components/chats/ChatItem/LinkPreview.tsx index 9858e477b..de41ed21a 100644 --- a/src/components/chats/ChatItem/LinkPreview.tsx +++ b/src/components/chats/ChatItem/LinkPreview.tsx @@ -39,6 +39,8 @@ export default function LinkPreview({ length: 300, }) + const isValidImage = linkMetadata.image?.startsWith('https://') + return (
{truncatedDesc}

- {linkMetadata.image && ( + {linkMetadata.image && isValidImage && ( ( replicated.textContent = (props.value ?? '') + ' ' }, [props.value]) + useEffect(() => { + const textArea = textAreaRef.current + const replicated = replicatedRef.current + if (!replicated || !textArea) return + replicated.textContent = textArea.value + ' ' + }, []) + const onKeyDown: KeyboardEventHandler = (e) => { if (!isTouchDevice() && e.key === 'Enter' && !e.shiftKey) { e.preventDefault() diff --git a/src/components/modals/MessageModal.tsx b/src/components/modals/MessageModal.tsx index 7c0f44dd9..072a50d8e 100644 --- a/src/components/modals/MessageModal.tsx +++ b/src/components/modals/MessageModal.tsx @@ -78,29 +78,34 @@ export default function MessageModal({ >
{message && ( - +
+ +
)} {scrollToMessage && ( - +
+ +
)}
{isDifferentRecipient && recipient && ( diff --git a/src/pages/api/posts.ts b/src/pages/api/posts.ts index 41e8d89f1..cb1f252ba 100644 --- a/src/pages/api/posts.ts +++ b/src/pages/api/posts.ts @@ -134,6 +134,7 @@ export async function getPostsServer(postIds: string[]): Promise { const getMetadataRedisKey = (url: string) => 'metadata:' + url const METADATA_MAX_AGE = 60 * 60 * 24 * 30 // 1 month +const METADATA_ERROR_MAX_AGE = 60 * 60 * 24 // 1 day async function getLinkMetadata(link: string): Promise { const cachedData = await redisCallWrapper((redis) => redis?.get(getMetadataRedisKey(link)) @@ -164,6 +165,14 @@ async function getLinkMetadata(link: string): Promise { return parsedMetadata } catch (err) { console.error('Error fetching page metadata for link: ', link) + redisCallWrapper((redis) => + redis?.set( + getMetadataRedisKey(link), + JSON.stringify(null), + 'EX', + METADATA_ERROR_MAX_AGE + ) + ) return null } } diff --git a/src/utils/ipfs.ts b/src/utils/ipfs.ts index a00bce200..d0f6263ee 100644 --- a/src/utils/ipfs.ts +++ b/src/utils/ipfs.ts @@ -21,14 +21,18 @@ export function getIpfsContentUrl( if (uri.startsWith('http')) return uri - const ipfsCid = CID.parse(uri) - if (!ipfsCid) return uri - - const isCbor = ipfsCid.code === CID_KIND.CBOR - if (isCbor) { - return urlJoin(SUBSOCIAL_IPFS_GATEWAY, `/api/v0/dag/get?arg=${uri}`) - } - return urlJoin(SUBSOCIAL_IPFS_GATEWAY, `/ipfs/${uri}`) + try { + const ipfsCid = CID.parse(uri) + if (!ipfsCid) return uri + + const isCbor = ipfsCid.code === CID_KIND.CBOR + if (isCbor) { + return urlJoin(SUBSOCIAL_IPFS_GATEWAY, `/api/v0/dag/get?arg=${uri}`) + } + return urlJoin(SUBSOCIAL_IPFS_GATEWAY, `/ipfs/${uri}`) + } catch {} + + return uri } export function getCidFromMetadataLink(link: string) {