@@ -174,6 +174,80 @@ const useScrollBehavior = (
174174 } ;
175175} ;
176176
177+ interface MessageContextProps {
178+ replyToMessageId ?: Id < "messages" > ;
179+ editingMessageId : Id < "messages" > | null ;
180+ messages : FunctionReturnType < typeof api . messages . getMessages > | undefined ;
181+ setReplyToMessageId : ( id : undefined ) => void ;
182+ scrollToMessage : ( messageId : Id < "messages" > ) => void ;
183+ }
184+
185+ const MessageContext : React . FC < MessageContextProps > = ( {
186+ replyToMessageId,
187+ editingMessageId,
188+ messages,
189+ setReplyToMessageId,
190+ scrollToMessage,
191+ } ) => {
192+ if ( ! replyToMessageId && ! editingMessageId ) return null ;
193+
194+ const message = messages ?. find (
195+ ( msg ) => msg . _id === ( replyToMessageId ?? editingMessageId ) ,
196+ ) ;
197+
198+ if ( ! message || message . type !== "message" ) return null ;
199+
200+ const isEditing = Boolean ( editingMessageId ) ;
201+ const contextText = isEditing ? "Editing message:" : "Replying to:" ;
202+ const handleClose = ( ) => {
203+ setReplyToMessageId ( undefined ) ;
204+ } ;
205+
206+ return (
207+ < AnimatePresence >
208+ < motion . div
209+ initial = { { opacity : 0 , translateY : 70 } }
210+ animate = { { opacity : 1 , translateY : 0 } }
211+ exit = { { opacity : 0 , translateY : 70 } }
212+ transition = { { duration : 0.5 } }
213+ >
214+ < div
215+ onMouseDown = { ( ) => {
216+ scrollToMessage ( message . _id ) ;
217+ } }
218+ className = "relative m-4 mb-2 cursor-pointer rounded-lg border border-secondary-foreground bg-secondary p-2"
219+ >
220+ < div className = "flex items-center justify-between" >
221+ < p className = "text-sm text-destructive-foreground" > { contextText } </ p >
222+ </ div >
223+ < button
224+ className = { cn (
225+ "absolute right-4 top-1/2 flex h-8 w-8 -translate-y-1/2 transform cursor-pointer items-center justify-center rounded-sm border-2 border-secondary-foreground bg-primary p-1 lg:h-10 lg:w-10 lg:p-2" ,
226+ editingMessageId ? "hidden" : "" ,
227+ ) }
228+ onMouseDown = { ( e ) => {
229+ e . stopPropagation ( ) ;
230+ handleClose ( ) ;
231+ } }
232+ aria-label = "Cancel reply"
233+ onKeyDown = { ( e ) => {
234+ if ( e . key === "Escape" ) {
235+ handleClose ( ) ;
236+ }
237+ } }
238+ >
239+ < X className = "h-4 w-4" />
240+ </ button >
241+
242+ < p className = "text-sm" >
243+ < strong > { message . from . username } </ strong > : { message . content }
244+ </ p >
245+ </ div >
246+ </ motion . div >
247+ </ AnimatePresence >
248+ ) ;
249+ } ;
250+
177251export default function Page ( ) {
178252 const params = useParams < { chatId : string } > ( ) ;
179253 const [ progress , setProgress ] = React . useState ( 13 ) ;
@@ -705,58 +779,13 @@ export default function Page() {
705779
706780 < div className = "flex w-full items-center justify-start" >
707781 < div className = "flex w-full flex-col gap-2" >
708- < AnimatePresence >
709- { replyToMessageId && (
710- < motion . div
711- initial = { { opacity : 0 , translateY : 70 } }
712- animate = { { opacity : 1 , translateY : 0 } }
713- exit = { { opacity : 0 , translateY : 70 } }
714- transition = { { duration : 0.5 } }
715- >
716- < div
717- onMouseDown = { ( ) => {
718- scrollToMessage ( replyToMessageId ) ;
719- } }
720- className = "relative m-4 mb-2 cursor-pointer rounded-lg border border-secondary-foreground bg-secondary p-2"
721- >
722- < div className = "flex items-center justify-between" >
723- < p className = "text-sm text-destructive-foreground" >
724- Replying to:
725- </ p >
726- </ div >
727- < button
728- className = "absolute right-4 top-1/2 flex h-8 w-8 -translate-y-1/2 transform cursor-pointer items-center justify-center rounded-sm border-2 border-secondary-foreground bg-primary p-1 lg:h-10 lg:w-10 lg:p-2"
729- onMouseDown = { ( e ) => {
730- e . stopPropagation ( ) ; // This prevents the parent's onMouseDown from firing
731- setReplyToMessageId ( undefined ) ;
732- } }
733- aria-label = "Cancel reply"
734- onKeyDown = { ( e ) => {
735- if ( e . key === "Escape" ) {
736- setReplyToMessageId ( undefined ) ;
737- }
738- } }
739- >
740- < X className = "h-4 w-4" />
741- </ button >
742-
743- < p className = "text-sm" >
744- { ( ( ) => {
745- const message = messages . data ?. find (
746- ( msg ) => msg . _id === replyToMessageId ,
747- ) ;
748- return message ?. type === "message" ? (
749- < >
750- < strong > { message . from . username } </ strong > :{ " " }
751- { message . content }
752- </ >
753- ) : null ;
754- } ) ( ) }
755- </ p >
756- </ div >
757- </ motion . div >
758- ) }
759- </ AnimatePresence >
782+ < MessageContext
783+ replyToMessageId = { replyToMessageId }
784+ editingMessageId = { editingMessageId }
785+ messages = { messages . data }
786+ setReplyToMessageId = { setReplyToMessageId }
787+ scrollToMessage = { scrollToMessage }
788+ />
760789 < div className = "z-10 flex w-full justify-between gap-8 bg-primary p-4 pb-10 lg:pb-4" >
761790 < Form { ...textMessageForm } >
762791 < form
0 commit comments