11"use client" ;
22
33import { theme } from "@/styles/theme.yak" ;
4- import { memo , useEffect , useMemo , useRef , useState } from "react" ;
4+ import { memo , useCallback , useEffect , useMemo , useRef , useState } from "react" ;
55import type { User } from "@supabase/supabase-js" ;
66
77import { createClient } from "@/utils/supabase/client" ;
@@ -85,6 +85,42 @@ function getChatDraftStorageKey({
8585 return `peels:chat-draft:${ userId } :${ threadId } ` ;
8686}
8787
88+ function readChatDraft ( key : string ) {
89+ if ( typeof window === "undefined" ) {
90+ return "" ;
91+ }
92+
93+ try {
94+ return window . sessionStorage . getItem ( key ) || "" ;
95+ } catch {
96+ return "" ;
97+ }
98+ }
99+
100+ function writeChatDraft ( key : string , message : string ) {
101+ if ( typeof window === "undefined" ) {
102+ return ;
103+ }
104+
105+ try {
106+ window . sessionStorage . setItem ( key , message ) ;
107+ } catch {
108+ // Ignore storage failures, such as private browsing restrictions.
109+ }
110+ }
111+
112+ function removeChatDraft ( key : string ) {
113+ if ( typeof window === "undefined" ) {
114+ return ;
115+ }
116+
117+ try {
118+ window . sessionStorage . removeItem ( key ) ;
119+ } catch {
120+ // Ignore storage failures, such as private browsing restrictions.
121+ }
122+ }
123+
88124function getClientTimeZone ( ) {
89125 return (
90126 Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ?? CHAT_RENDER_TIME_ZONE
@@ -247,14 +283,14 @@ const ChatWindow = memo(function ChatWindow({
247283 return errorMessage ;
248284 }
249285
250- function clearPendingDraftWrite ( ) {
286+ const clearPendingDraftWrite = useCallback ( ( ) => {
251287 if ( draftWriteTimeoutRef . current ) {
252288 clearTimeout ( draftWriteTimeoutRef . current ) ;
253289 draftWriteTimeoutRef . current = null ;
254290 }
255- }
291+ } , [ ] ) ;
256292
257- function flushPendingDraftWrite ( ) {
293+ const flushPendingDraftWrite = useCallback ( ( ) => {
258294 clearPendingDraftWrite ( ) ;
259295
260296 if ( ! pendingDraftWriteRef . current ) {
@@ -263,28 +299,55 @@ const ChatWindow = memo(function ChatWindow({
263299
264300 const { key, message } = pendingDraftWriteRef . current ;
265301 pendingDraftWriteRef . current = null ;
266- sessionStorage . setItem ( key , message ) ;
267- }
302+ writeChatDraft ( key , message ) ;
303+ } , [ clearPendingDraftWrite ] ) ;
268304
269- function scheduleDraftWrite ( key : string , nextMessage : string ) {
270- clearPendingDraftWrite ( ) ;
271- pendingDraftWriteRef . current = {
272- key,
273- message : nextMessage ,
274- } ;
275- draftWriteTimeoutRef . current = setTimeout ( ( ) => {
305+ const scheduleDraftWrite = useCallback (
306+ ( key : string , nextMessage : string ) => {
307+ clearPendingDraftWrite ( ) ;
308+ pendingDraftWriteRef . current = {
309+ key,
310+ message : nextMessage ,
311+ } ;
312+ draftWriteTimeoutRef . current = setTimeout ( ( ) => {
313+ flushPendingDraftWrite ( ) ;
314+ } , CHAT_DRAFT_WRITE_DELAY_MS ) ;
315+ } ,
316+ [ clearPendingDraftWrite , flushPendingDraftWrite ]
317+ ) ;
318+
319+ const removeDraftWrite = useCallback (
320+ ( key : string ) => {
321+ if ( pendingDraftWriteRef . current ?. key === key ) {
322+ clearPendingDraftWrite ( ) ;
323+ pendingDraftWriteRef . current = null ;
324+ }
325+
326+ removeChatDraft ( key ) ;
327+ } ,
328+ [ clearPendingDraftWrite ]
329+ ) ;
330+
331+ useEffect ( ( ) => {
332+ const handlePageHide = ( ) => {
276333 flushPendingDraftWrite ( ) ;
277- } , CHAT_DRAFT_WRITE_DELAY_MS ) ;
278- }
334+ } ;
335+ const handleVisibilityChange = ( ) => {
336+ if ( document . visibilityState === "hidden" ) {
337+ flushPendingDraftWrite ( ) ;
338+ }
339+ } ;
279340
280- function removeDraftWrite ( key : string ) {
281- if ( pendingDraftWriteRef . current ?. key === key ) {
282- clearPendingDraftWrite ( ) ;
283- pendingDraftWriteRef . current = null ;
284- }
341+ window . addEventListener ( "beforeunload" , handlePageHide ) ;
342+ window . addEventListener ( "pagehide" , handlePageHide ) ;
343+ document . addEventListener ( "visibilitychange" , handleVisibilityChange ) ;
285344
286- sessionStorage . removeItem ( key ) ;
287- }
345+ return ( ) => {
346+ window . removeEventListener ( "beforeunload" , handlePageHide ) ;
347+ window . removeEventListener ( "pagehide" , handlePageHide ) ;
348+ document . removeEventListener ( "visibilitychange" , handleVisibilityChange ) ;
349+ } ;
350+ } , [ flushPendingDraftWrite ] ) ;
288351
289352 useEffect ( ( ) => {
290353 setClientTimeZone ( getClientTimeZone ( ) ) ;
@@ -294,17 +357,15 @@ const ChatWindow = memo(function ChatWindow({
294357 flushPendingDraftWrite ( ) ;
295358 setThreadId ( existingThread ?. id ?? null ) ;
296359 setMessages ( getThreadMessages ( existingThread ) ) ;
297- setMessage (
298- draftStorageKey ? sessionStorage . getItem ( draftStorageKey ) || "" : ""
299- ) ;
360+ setMessage ( draftStorageKey ? readChatDraft ( draftStorageKey ) : "" ) ;
300361 lastReadSignatureRef . current = null ;
301- } , [ draftStorageKey , existingThread ] ) ;
362+ } , [ draftStorageKey , existingThread , flushPendingDraftWrite ] ) ;
302363
303364 useEffect (
304365 ( ) => ( ) => {
305366 flushPendingDraftWrite ( ) ;
306367 } ,
307- [ ]
368+ [ flushPendingDraftWrite ]
308369 ) ;
309370
310371 useEffect ( ( ) => {
0 commit comments