|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|