import clsx from 'clsx' import {MAX_COMMENT_LENGTH} from 'common/comment' import {Profile} from 'common/profiles/profile' import {User} from 'common/user' import {findKey} from 'lodash' import {useRouter} from 'next/router' import {useEffect, useState} from 'react' import {BiEnvelope} from 'react-icons/bi' import {Button} from 'web/components/buttons/button' import {CommentInputTextArea} from 'web/components/comments/comment-input' import {Col} from 'web/components/layout/col' import {Modal, MODAL_CLASS} from 'web/components/layout/modal' import {EmailVerificationPrompt} from 'web/components/messaging/email-verification-prompt' import {useTextEditor} from 'web/components/widgets/editor' import {Tooltip} from 'web/components/widgets/tooltip' import {useFirebaseUser} from 'web/hooks/use-firebase-user' import {useSortedPrivateMessageMemberships} from 'web/hooks/use-private-messages' import {usePrivateUser} from 'web/hooks/use-user' import {api} from 'web/lib/api' import {firebaseLogin} from 'web/lib/firebase/users' import {useT} from 'web/lib/locale' export const SendMessageButton = (props: { toUser: User currentUser: User | undefined | null profile: Profile includeLabel?: boolean circleButton?: boolean text?: string tooltipText?: string disabled?: boolean }) => { const {toUser, currentUser, profile, includeLabel, circleButton, text, tooltipText, disabled} = props const firebaseUser = useFirebaseUser() const router = useRouter() const privateUser = usePrivateUser() const channelMemberships = useSortedPrivateMessageMemberships(currentUser?.id) const {memberIdsByChannelId} = channelMemberships const t = useT() const [openComposeModal, setOpenComposeModal] = useState(false) const [error, setError] = useState('') const [submitting, setSubmitting] = useState(false) const messageButtonClicked = async () => { if (disabled) return if (!currentUser) return firebaseLogin() const previousDirectMessageChannel = findKey( memberIdsByChannelId, (dm) => dm.includes(toUser.id) && dm.length === 1, ) const previousChannelId = previousDirectMessageChannel !== undefined ? previousDirectMessageChannel : undefined if (previousChannelId) router.push(`/messages/${previousChannelId}`) else setOpenComposeModal(true) } const editor = useTextEditor({ key: `compose-new-message-${toUser.id}`, size: 'sm', max: MAX_COMMENT_LENGTH, placeholder: t( 'send_message.placeholder', `What genuinely resonated with you in {name}'s profile? What would you like to explore together?`, {name: toUser.name}, ), className: 'min-h-[150px]', nRowsMin: 3, }) useEffect(() => { if (openComposeModal && editor) { // Focus the editor after a short delay to ensure the modal is fully rendered setTimeout(() => { editor.commands.focus() }, 100) } }, [openComposeModal, editor]) const sendMessage = async () => { if (!editor) return setSubmitting(true) const res = await api('create-private-user-message-channel', { userIds: [toUser.id], }).catch((e) => { setError(e.message) setSubmitting(false) return }) if (!res) return const msgRes = await api('create-private-user-message', { channelId: res.channelId, content: editor.getJSON(), }).catch((e: any) => { setError(e.message) setSubmitting(false) return }) if (!msgRes) return router.push(`/messages/${res.channelId}`) } const [insertedChips, setInsertedChips] = useState([]) const toggleChip = (label: string) => { if (!editor) return const alreadyInserted = insertedChips.includes(label) if (alreadyInserted) { // remove the token from the editor text const current = editor.getText() const cleaned = current.replace(new RegExp(`\\s?${label}`, 'gi'), '').trim() editor.commands.setContent(cleaned) setInsertedChips((prev) => prev.filter((c) => c !== label)) } else { // append at cursor (or end) editor.chain().focus().insertContent(` ${label}`).run() setInsertedChips((prev) => [...prev, label]) } } const MIN_CHARS = 200 const charCount = editor?.getText().trim().length ?? 0 const pct = Math.min((charCount / MIN_CHARS) * 100, 100) // Smooth color transition from red (0%) to green (100%) const r = pct < 50 ? 255 : Math.round(((100 - pct) / 50) * 255) const g = pct < 50 ? Math.round((pct / 50) * 255) : 255 const b = Math.round(0) const barColor = `rgb(${r}, ${g}, ${b})` if (privateUser?.blockedByUserIds.includes(toUser.id)) return null return ( <> {text ? ( ) : circleButton ? ( ) : ( )}

{t('send_message.title', 'Start a meaningful conversation')}

{t( 'send_message.guidance', 'Compass is about depth. Take a moment to write something genuine.', )}

{firebaseUser?.emailVerified ? ( <> {!!profile.keywords?.length && (

{t( 'send_message.keywords_hint', `Insert some of {name}'s topics in your message`, {name: toUser.name}, )}

{profile.keywords.map((k) => ( ))}
)}

{t( 'send_message.min_chars_hint', 'Write at least {count} characters to unlock the send button', {count: MIN_CHARS}, )}

{/* quality meter */}
{charCount < MIN_CHARS ? `${charCount}` : t('send_message.ready', 'Ready to send')}
) : ( )} {error && ( {error} )} ) }