2026-09-24 12:51:18 -04:00
import React , { useCallback , useEffect , useState } from 'react' ;
import FocusTrap from 'focus-trap-react' ;
import {
Box ,
Button ,
Checkbox ,
Dialog ,
Header ,
Overlay ,
OverlayBackdrop ,
OverlayCenter ,
Text ,
config ,
} from 'folds' ;
import { invokeTauri , isTauri , tauriInvoke , useTauriEvent } from '../hooks/useTauri' ;
import { useModalStyle } from '../hooks/useModalStyle' ;
/**
* cinny-desktop #5: the first time the window is closed, ask whether Lotus Chat
* should keep running in the tray (calls, messages, notifications) or quit —
* and, in the same moment, whether it should start when you sign in. Asked
* once; changeable in Settings → General. The native side sends
* `lotus-close-requested` only while the choice is still "ask", and never
* during a call (a call always goes to the tray).
*/
export function CloseBehaviorPrompt() {
const [ open , setOpen ] = useState ( false );
const [ launchOnLogin , setLaunchOnLogin ] = useState ( false );
2026-10-18 02:41:04 -04:00
// [cinny-desktop #37] Stock GNOME has no tray host: "keep running in the
// tray" would hide the window with no icon to bring it back. Older desktop
// builds lack the command; assume a tray then (the old behaviour).
const [ hasTray , setHasTray ] = useState ( true );
2026-09-24 12:51:18 -04:00
const modalStyle = useModalStyle ( 420 );
// Tells the native side we're listening (see get_close_behavior).
useEffect (() => {
if ( ! isTauri ()) return ;
tauriInvoke () ? .( 'get_close_behavior' ). catch (() => undefined );
}, []);
2026-10-18 02:41:04 -04:00
useTauriEvent ( 'lotus-close-requested' , () => {
const ask = tauriInvoke () ? .( 'has_tray_host' );
if ( ! ask ) {
setOpen ( true );
return ;
}
ask
. then (( v ) => setHasTray ( v !== false ))
. catch (() => setHasTray ( true ))
. finally (() => setOpen ( true ));
});
2026-09-24 12:51:18 -04:00
const choose = useCallback (
( value : 'tray' | 'quit' ) => {
if ( launchOnLogin ) invokeTauri ( 'plugin:autostart|enable' );
setOpen ( false );
invokeTauri ( 'resolve_close_request' , { value });
},
[ launchOnLogin ],
);
if ( ! open ) return null ;
return (
< Overlay open backdrop = {< OverlayBackdrop />}>
< OverlayCenter >
< FocusTrap
focusTrapOptions = {{
2026-10-18 02:41:04 -04:00
initialFocus : hasTray ? '#close-behavior-keep' : '#close-behavior-quit' ,
2026-09-24 12:51:18 -04:00
// Dismissing without choosing keeps the window open; the next close
// asks again.
onDeactivate : () => setOpen ( false ),
clickOutsideDeactivates : true ,
}}
>
< Dialog
variant = "Surface"
role = "dialog"
aria-modal = "true"
aria-labelledby = "close-behavior-title"
aria-describedby = "close-behavior-body"
style = { modalStyle }
>
< Header
style = {{
padding : `0 ${ config . space . S400 } ` ,
borderBottomWidth : config.borderWidth.B300 ,
}}
variant = "Surface"
size = "500"
>
< Text as = "h2" size = "H4" id = "close-behavior-title" >
Keep Lotus Chat running ?
</ Text >
</ Header >
< Box style = {{ padding : config.space.S400 }} direction = "Column" gap = "400" >
< Text priority = "400" id = "close-behavior-body" >
2026-10-18 02:41:04 -04:00
{ hasTray
? 'Lotus Chat can keep running in the system tray when you close this window, so messages, notifications and calls still reach you. Open it again from the tray icon.'
: "Your desktop doesn't show tray icons, so if Lotus Chat keeps running after you close this window, the only way back is to launch it again." }
2026-09-24 12:51:18 -04:00
</ Text >
< Box as = "label" alignItems = "Center" gap = "200" style = {{ cursor : 'pointer' }}>
< Checkbox
size = "300"
variant = "Primary"
checked = { launchOnLogin }
onClick = {( e : React.MouseEvent < HTMLInputElement >) =>
setLaunchOnLogin ( e . currentTarget . checked )
}
/>
< Text size = "T300" > Start Lotus Chat when I sign in to my computer </ Text >
</ Box >
< Box direction = "Column" gap = "200" >
2026-10-18 02:41:04 -04:00
{ hasTray ? (
<>
< Button
id = "close-behavior-keep"
variant = "Primary"
onClick = {() => choose ( 'tray' )}
>
< Text size = "B400" > Keep running in the tray </ Text >
</ Button >
< Button
id = "close-behavior-quit"
variant = "Secondary"
fill = "Soft"
onClick = {() => choose ( 'quit' )}
>
< Text size = "B400" > Quit when I close the window </ Text >
</ Button >
</>
) : (
<>
< Button
id = "close-behavior-quit"
variant = "Primary"
onClick = {() => choose ( 'quit' )}
>
< Text size = "B400" > Quit when I close the window </ Text >
</ Button >
< Button
id = "close-behavior-keep"
variant = "Secondary"
fill = "Soft"
onClick = {() => choose ( 'tray' )}
>
< Text size = "B400" > Keep running in the background </ Text >
</ Button >
</>
)}
2026-09-24 12:51:18 -04:00
</ Box >
< Text size = "T200" priority = "300" >
You can change this in Settings → General .
</ Text >
</ Box >
</ Dialog >
</ FocusTrap >
</ OverlayCenter >
</ Overlay >
);
}