You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			107 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			107 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
| import React from 'react';
 | |
| 
 | |
| import { RenderTextCallbackType } from '../../types/Util';
 | |
| import classNames from 'classnames';
 | |
| import { MultiDeviceProtocol } from '../../session/protocols';
 | |
| import { FindMember } from '../../util';
 | |
| import { useInterval } from '../../hooks/useInterval';
 | |
| import { ConversationModel } from '../../../js/models/conversations';
 | |
| 
 | |
| interface MentionProps {
 | |
|   key: string;
 | |
|   text: string;
 | |
|   convoId: string;
 | |
| }
 | |
| 
 | |
| const Mention = (props: MentionProps) => {
 | |
|   const [found, setFound] = React.useState<ConversationModel | null>(null);
 | |
|   const [us, setUs] = React.useState(false);
 | |
| 
 | |
|   const tryRenameMention = async () => {
 | |
|     if (!found) {
 | |
|       const foundMember = await FindMember.findMember(
 | |
|         props.text.slice(1),
 | |
|         props.convoId
 | |
|       );
 | |
| 
 | |
|       if (foundMember) {
 | |
|         const itsUs = await MultiDeviceProtocol.isOurDevice(foundMember.id);
 | |
|         setUs(itsUs);
 | |
|         setFound(foundMember);
 | |
|         // FIXME stop this interval once we found it.
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   useInterval(() => void tryRenameMention(), 10000);
 | |
| 
 | |
|   if (found) {
 | |
|     // TODO: We don't have to search the database of message just to know that the message is for us!
 | |
|     const className = classNames(
 | |
|       'mention-profile-name',
 | |
|       us && 'mention-profile-name-us'
 | |
|     );
 | |
| 
 | |
|     const displayedName = found.getContactProfileNameOrShortenedPubKey();
 | |
|     return <span className={className}>{displayedName}</span>;
 | |
|   } else {
 | |
|     return (
 | |
|       <span className="mention-profile-name">
 | |
|         {window.shortenPubkey(props.text)}
 | |
|       </span>
 | |
|     );
 | |
|   }
 | |
| };
 | |
| 
 | |
| interface Props {
 | |
|   text: string;
 | |
|   renderOther?: RenderTextCallbackType;
 | |
|   convoId: string;
 | |
| }
 | |
| 
 | |
| export class AddMentions extends React.Component<Props> {
 | |
|   public static defaultProps: Partial<Props> = {
 | |
|     renderOther: ({ text }) => text,
 | |
|   };
 | |
| 
 | |
|   public render() {
 | |
|     const { text, renderOther, convoId } = this.props;
 | |
|     const results: Array<any> = [];
 | |
|     const FIND_MENTIONS = window.pubkeyPattern;
 | |
| 
 | |
|     // We have to do this, because renderNonNewLine is not required in our Props object,
 | |
|     //  but it is always provided via defaultProps.
 | |
|     if (!renderOther) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let match = FIND_MENTIONS.exec(text);
 | |
|     let last = 0;
 | |
|     let count = 1000;
 | |
| 
 | |
|     if (!match) {
 | |
|       return renderOther({ text, key: 0 });
 | |
|     }
 | |
|     while (match) {
 | |
|       count++;
 | |
|       const key = count;
 | |
|       if (last < match.index) {
 | |
|         const otherText = text.slice(last, match.index);
 | |
|         results.push(renderOther({ text: otherText, key }));
 | |
|       }
 | |
| 
 | |
|       const pubkey = text.slice(match.index, FIND_MENTIONS.lastIndex);
 | |
|       results.push(<Mention text={pubkey} key={`${key}`} convoId={convoId} />);
 | |
| 
 | |
|       last = FIND_MENTIONS.lastIndex;
 | |
|       match = FIND_MENTIONS.exec(text);
 | |
|     }
 | |
| 
 | |
|     if (last < text.length) {
 | |
|       results.push(renderOther({ text: text.slice(last), key: count++ }));
 | |
|     }
 | |
| 
 | |
|     return results;
 | |
|   }
 | |
| }
 |