@@ -37,10 +37,10 @@ import { useDraft } from '@/src/stores/draft-store';
37
37
import { Editor } from '@/src/components/editor' ;
38
38
import { type TypeId } from '@u22n/utils/typeid' ;
39
39
import { useDebounce } from '@uidotdev/usehooks' ;
40
- import { useAtom , useAtomValue } from 'jotai' ;
41
40
import { platform } from '@/src/lib/trpc' ;
42
41
import { cn } from '@/src/lib/utils' ;
43
42
import { ms } from '@u22n/utils/ms' ;
43
+ import { useAtom } from 'jotai' ;
44
44
import { toast } from 'sonner' ;
45
45
46
46
type ReplyBoxProps = {
@@ -58,7 +58,8 @@ export function ReplyBox({
58
58
const [ editorText , setEditorText ] = useState ( draft . content ) ;
59
59
const orgShortcode = useOrgShortcode ( ) ;
60
60
const spaceShortcode = useSpaceShortcode ( false ) ;
61
- const replyTo = useAtomValue ( replyToMessageAtom ) ;
61
+ const [ replyTo ] = useAtom ( replyToMessageAtom ) ;
62
+ const [ emailIdentity , setEmailIdentity ] = useAtom ( emailIdentityAtom ) ;
62
63
const addConvoToCache = useUpdateConvoMessageList$Cache ( ) ;
63
64
const updateConvoData = useUpdateConvoData$Cache ( ) ;
64
65
const editorRef = useRef < EditorFunctions > ( null ) ;
@@ -116,8 +117,6 @@ export function ReplyBox({
116
117
}
117
118
) ;
118
119
119
- const [ emailIdentity , setEmailIdentity ] = useAtom ( emailIdentityAtom ) ;
120
-
121
120
const {
122
121
attachments,
123
122
openFilePicker,
@@ -148,7 +147,11 @@ export function ReplyBox({
148
147
149
148
const handleReply = useCallback (
150
149
async ( type : 'comment' | 'message' ) => {
151
- if ( ! replyTo ) return ;
150
+ const currentReplyTo = replyTo ;
151
+ if ( ! currentReplyTo ) {
152
+ console . error ( 'ReplyBox: replyTo is null' ) ;
153
+ return ;
154
+ }
152
155
if ( hasExternalParticipants && emailIdentity === null ) {
153
156
toast . error ( 'Please select an email identity to send the message as.' ) ;
154
157
return ;
@@ -158,7 +161,7 @@ export function ReplyBox({
158
161
attachments : getTrpcUploadFormat ( ) ,
159
162
orgShortcode,
160
163
message : editorText ,
161
- replyToMessagePublicId : replyTo ,
164
+ replyToMessagePublicId : currentReplyTo ,
162
165
messageType : type ,
163
166
sendAsEmailIdentityPublicId : emailIdentity ?? undefined
164
167
} ) ;
@@ -190,6 +193,7 @@ export function ReplyBox({
190
193
onReply ( ) ;
191
194
} ,
192
195
[
196
+ replyTo ,
193
197
addConvoToCache ,
194
198
convoId ,
195
199
editorText ,
@@ -198,13 +202,45 @@ export function ReplyBox({
198
202
hasExternalParticipants ,
199
203
onReply ,
200
204
orgShortcode ,
201
- replyTo ,
202
205
replyToConvo ,
203
206
spaceShortcode ,
204
207
updateConvoData
205
208
]
206
209
) ;
207
210
211
+ const handleSendMessage = useCallback ( ( ) => {
212
+ if (
213
+ ! replyTo ||
214
+ isEditorEmpty ||
215
+ ( hasExternalParticipants && ! emailIdentity ) ||
216
+ replyToConvoLoading
217
+ ) {
218
+ return ;
219
+ }
220
+ return handleReply ( 'message' ) ;
221
+ } , [
222
+ replyTo ,
223
+ isEditorEmpty ,
224
+ hasExternalParticipants ,
225
+ emailIdentity ,
226
+ replyToConvoLoading ,
227
+ handleReply
228
+ ] ) ;
229
+
230
+ useEffect ( ( ) => {
231
+ const handleKeyDown = ( event : KeyboardEvent ) => {
232
+ if ( ( event . metaKey || event . ctrlKey ) && event . key === 'Enter' ) {
233
+ event . preventDefault ( ) ;
234
+ void handleSendMessage ( ) ;
235
+ }
236
+ } ;
237
+
238
+ document . addEventListener ( 'keydown' , handleKeyDown ) ;
239
+ return ( ) => {
240
+ document . removeEventListener ( 'keydown' , handleKeyDown ) ;
241
+ } ;
242
+ } , [ handleSendMessage ] ) ;
243
+
208
244
return (
209
245
< div className = "flex min-h-32 flex-col p-4" >
210
246
< div
@@ -328,10 +364,7 @@ export function ReplyBox({
328
364
replyToConvoLoading
329
365
}
330
366
size = { isMobile ? 'icon' : 'sm' }
331
- onPointerDown = { ( e ) => {
332
- e . preventDefault ( ) ;
333
- return handleReply ( 'message' ) ;
334
- } } >
367
+ onClick = { handleSendMessage } >
335
368
{ isMobile ? < PaperPlaneTilt size = { 16 } /> : < span > Send</ span > }
336
369
</ Button >
337
370
</ div >
0 commit comments