import React, {useEffect, useRef, useState} from 'react'; import { Keyboard, KeyboardAvoidingView, Platform, StyleSheet, TextInput, View, } from 'react-native'; import {TouchableOpacity} from 'react-native-gesture-handler'; import ParsedText, {ParseShape} from 'react-native-parsed-text'; import {useDispatch, useSelector} from 'react-redux'; import UpArrowIcon from '../../assets/icons/up_arrow.svg'; import {TAGG_LIGHT_BLUE} from '../../constants'; import {postComment} from '../../services'; import {updateReplyPosted} from '../../store/actions'; import {RootState} from '../../store/rootreducer'; import {ProfilePreviewType} from '../../types'; import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; import {Avatar, TaggTypeahead} from '../common'; /** * This file provides the add comment view for a user. * Displays the logged in user's profile picture to the left and then provides space to add a comment. * Comment is posted when enter is pressed as requested by product team. */ export interface AddCommentProps { setNewCommentsAvailable: Function; objectId: string; placeholderText: string; isCommentInFocus: boolean; } const AddComment: React.FC = ({ setNewCommentsAvailable, objectId, placeholderText, isCommentInFocus, }) => { const [comment, setComment] = useState(''); const [keyboardVisible, setKeyboardVisible] = useState(false); const [isMentioning, setIsMentioning] = useState(false); const [mentionQuery, setMentionQuery] = useState(''); const [selectedMention, setSelectedMention] = useState(); const [mentions, setMentions] = useState([]); const {avatar} = useSelector((state: RootState) => state.user); const dispatch = useDispatch(); const ref = useRef(null); const [parsePatterns, setParsePatterns] = useState([]); const addComment = async () => { const trimmed = comment.trim(); if (trimmed === '') { return; } const postedComment = await postComment( trimmed, objectId, isCommentInFocus, ); if (postedComment) { setComment(''); //Set new reply posted object //This helps us show the latest reply on top //Data set is kind of stale but it works if (isCommentInFocus) { dispatch( updateReplyPosted({ comment_id: postedComment.comment_id, parent_comment: {comment_id: objectId}, }), ); } setNewCommentsAvailable(true); } }; useEffect(() => { setParsePatterns( mentions.map((m) => ({ pattern: new RegExp(`@${m.username}`), style: {color: TAGG_LIGHT_BLUE}, })), ); }, [mentions]); useEffect(() => { if (selectedMention) { setComment( comment.replace( new RegExp(`@${mentionQuery}`), `@${selectedMention.username} `, ), ); setMentions([...mentions, selectedMention]); setSelectedMention(undefined); setMentionQuery(''); setIsMentioning(false); } }, [selectedMention]); useEffect(() => { const showKeyboard = () => setKeyboardVisible(true); Keyboard.addListener('keyboardWillShow', showKeyboard); return () => Keyboard.removeListener('keyboardWillShow', showKeyboard); }, []); useEffect(() => { const hideKeyboard = () => setKeyboardVisible(false); Keyboard.addListener('keyboardWillHide', hideKeyboard); return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard); }, []); //If a comment is in Focus, bring the keyboard up so user is able to type in a reply useEffect(() => { if (isCommentInFocus) { ref.current?.focus(); } }, [isCommentInFocus]); return ( {isMentioning && ( )} { const newestChar = newText[newText.length - 1]; const deletedChar = newText.length === comment.length - 1 ? comment[comment.length - 1] : undefined; if (newestChar === ' ' || deletedChar === '@') { setIsMentioning(false); setMentionQuery(''); } if (newestChar === '@') { setIsMentioning(true); } if (isMentioning) { const match = newText.match(/.*@(.*)$/); if (match) { setMentionQuery(match[1]); } } setComment(newText); }} multiline={true} ref={ref}> {comment} ); }; const styles = StyleSheet.create({ container: { backgroundColor: '#f7f7f7', alignItems: 'center', width: SCREEN_WIDTH, }, textContainer: { width: '95%', flexDirection: 'row', backgroundColor: '#e8e8e8', alignItems: 'center', justifyContent: 'space-between', margin: '3%', borderRadius: 25, }, text: { flex: 1, padding: '1%', marginHorizontal: '1%', maxHeight: 100, }, avatar: { height: 35, width: 35, borderRadius: 30, marginRight: 10, marginLeft: '3%', marginVertical: '2%', alignSelf: 'flex-end', }, submitButton: { height: 35, width: 35, backgroundColor: TAGG_LIGHT_BLUE, borderRadius: 999, justifyContent: 'center', alignItems: 'center', marginRight: '3%', marginVertical: '2%', alignSelf: 'flex-end', }, whiteBackround: { backgroundColor: '#fff', }, }); export default AddComment;