import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from "react"; import { Text, TextInput, TouchableOpacity, View, Keyboard, TextInputKeyPressEventData, NativeSyntheticEvent, Alert, } from "react-native"; import { handleError, useUser, useCommentSection, useMentions, useProject, } from "@replyke/core"; import { resetButton, resetTextInput, resetView, UserAvatar, useTextInputCursorIndicator, EmojiSuggestions, GiphyContainer, } from "@replyke/ui-core-react-native"; import { useSocialStyleConfig } from "@replyke/comments-social-core"; import ReplyBanner from "./ReplyBanner"; import MentionSuggestions from "./MentionSuggestions"; function NewCommentForm({ withEmojis = true, ref, }: { withEmojis?: boolean; ref?: React.Ref<{ focus: () => void }>; }) { const { user } = useUser(); const { project } = useProject(); const giphyApiKey = project?.integrations.find((int) => int.name === "giphy") ?.data.apiKey; const { pushMention, createComment, submittingComment, callbacks } = useCommentSection(); const { styleConfig } = useSocialStyleConfig(); const [isGiphyVisible, setIsGiphyVisible] = useState(false); const { backgroundColor, withAvatar, itemsGap, verticalPadding, paddingLeft, paddingRight, authorAvatarSize, placeholderText, textareaTextSize, textareaTextColor, textareaBackgroundColor, postButtonText, postButtonFontSize, postButtonFontColor, postButtonFontWeight, } = styleConfig!.newCommentFormProps; const textAreaRef = useRef(null); const [content, setContent] = useState(""); const { cursorPosition, isSelectionActive, handleSelectionChange, handleTextChange, } = useTextInputCursorIndicator(); const { isMentionActive, loading, mentionSuggestions, handleMentionClick, mentions, addMention, resetMentions, } = useMentions({ content, setContent, focus: () => textAreaRef.current?.focus(), cursorPosition, isSelectionActive, }); const handleCreateComment = useCallback(async () => { const tempContent = content; try { setContent(""); Keyboard.dismiss(); // Dismiss the keyboard await createComment!({ content, mentions }); resetMentions(); } catch (err) { setContent(tempContent); handleError(err, "Creating comment failed: "); } }, [createComment, mentions, resetMentions, callbacks, user]); const handleCreateGif = useCallback( async (gif: { id: string; url: string; gifUrl: string; gifPreviewUrl: string; altText: string | undefined; aspectRatio: number; }) => { setContent(""); resetMentions(); setIsGiphyVisible(false); try { await createComment!({ gif, mentions }); } catch (err) { handleError(err, "Creating comment failed: "); } }, [createComment, mentions, resetMentions, callbacks, user] ); useEffect(() => { if (!pushMention) return; const textArea = textAreaRef.current; if (!textArea) throw new Error("Can't find textarea"); // if (pushMention.id === previousPushMention?.id) return; if (!pushMention.username) { ( callbacks?.userCantBeMentionedCallback ?? (() => Alert.alert("User has no username")) )(); return; } addMention(pushMention); setContent((prevContent) => `@${pushMention.username} ${prevContent}`); }, [pushMention]); const handleKeyPress = useCallback( (event: NativeSyntheticEvent) => { if (event.nativeEvent.key === "Enter") { handleCreateComment(); } // If you want Shift+Enter or Ctrl+Enter to create a new line, you can leave this as-is. }, [handleCreateComment] ); const adjustTextareaHeight = () => { const textArea = textAreaRef.current; if (textArea) { textArea.measure((fx, fy, width, height, px, py) => { const baseHeight = 20; // Example base height in pixels. Adjust this value to match your design. const newHeight = Math.max(baseHeight, Math.min(100, height)); textArea.setNativeProps({ style: { height: newHeight }, }); }); } }; // useEffect(() => { // adjustTextareaHeight(); // }, [body]); useLayoutEffect(() => { const timeout = setTimeout(() => adjustTextareaHeight(), 500); return () => clearTimeout(timeout); }, []); // Expose the focus method to the parent through the forwarded ref useImperativeHandle(ref, () => ({ focus: () => { textAreaRef.current?.focus(); }, })); return ( <> {giphyApiKey ? ( setIsGiphyVisible(false)} onSelectGif={(selected) => handleCreateGif(selected)} visible={isGiphyVisible} /> ) : null} {withEmojis && ( { setContent((c) => c + emoji); }} /> )} {user && withAvatar && ( )} { setContent(text); handleTextChange(text); }} onSelectionChange={handleSelectionChange} onKeyPress={handleKeyPress} onSubmitEditing={() => handleCreateComment()} blurOnSubmit={false} style={{ ...resetTextInput, flex: 1, marginHorizontal: 8, fontSize: textareaTextSize, backgroundColor: textareaBackgroundColor, color: textareaTextColor, }} /> {content.length === 0 && giphyApiKey ? ( setIsGiphyVisible(true)} disabled={submittingComment} style={{ ...resetButton }} > GIF ) : ( {postButtonText} )} ); } NewCommentForm.displayName = "NewCommentForm"; export default NewCommentForm;