✨(frontend) add user setting to disable idle disconnect feature
Allow users to opt-out of idle participant disconnection despite default enforcement, trusting power users who modify this setting won't forget to disconnect, though accepting risk they may block maintenance configuration updates.
This commit is contained in:
committed by
aleb_the_flash
parent
39be4697b0
commit
dbc66c2f07
@@ -8,6 +8,8 @@ import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalytics
|
||||
import posthog from 'posthog-js'
|
||||
import { connectionObserverStore } from '@/stores/connectionObserver'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
import { userPreferencesStore } from '@/stores/userPreferences'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export const useConnectionObserver = () => {
|
||||
const room = useRoomContext()
|
||||
@@ -16,6 +18,8 @@ export const useConnectionObserver = () => {
|
||||
const { data } = useConfig()
|
||||
const isAnalyticsEnabled = useIsAnalyticsEnabled()
|
||||
|
||||
const userPreferencesSnap = useSnapshot(userPreferencesStore)
|
||||
|
||||
const idleDisconnectModalTimeoutRef = useRef<ReturnType<
|
||||
typeof setTimeout
|
||||
> | null>(null)
|
||||
@@ -34,10 +38,11 @@ export const useConnectionObserver = () => {
|
||||
idleDisconnectModalTimeoutRef.current = null
|
||||
}
|
||||
|
||||
const isEnabled = userPreferencesSnap.is_idle_disconnect_modal_enabled
|
||||
const delay = data?.idle_disconnect_warning_delay
|
||||
|
||||
// Disabled or invalid delay: ensure modal is closed
|
||||
if (!delay) {
|
||||
if (!isEnabled || !delay) {
|
||||
connectionObserverStore.isIdleDisconnectModalOpen = false
|
||||
return
|
||||
}
|
||||
@@ -56,7 +61,11 @@ export const useConnectionObserver = () => {
|
||||
idleDisconnectModalTimeoutRef.current = null
|
||||
}
|
||||
}
|
||||
}, [remoteParticipants.length, data?.idle_disconnect_warning_delay])
|
||||
}, [
|
||||
remoteParticipants.length,
|
||||
data?.idle_disconnect_warning_delay,
|
||||
userPreferencesSnap.is_idle_disconnect_modal_enabled,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAnalyticsEnabled) return
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Field, H } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLanguageLabels } from '@/i18n/useLanguageLabels'
|
||||
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||
import { userPreferencesStore } from '@/stores/userPreferences'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export type GeneralTabProps = Pick<TabPanelProps, 'id'>
|
||||
|
||||
@@ -9,6 +11,8 @@ export const GeneralTab = ({ id }: GeneralTabProps) => {
|
||||
const { t, i18n } = useTranslation('settings')
|
||||
const { languagesList, currentLanguage } = useLanguageLabels()
|
||||
|
||||
const userPreferencesSnap = useSnapshot(userPreferencesStore)
|
||||
|
||||
return (
|
||||
<TabPanel padding={'md'} flex id={id}>
|
||||
<H lvl={2}>{t('language.heading')}</H>
|
||||
@@ -21,6 +25,20 @@ export const GeneralTab = ({ id }: GeneralTabProps) => {
|
||||
i18n.changeLanguage(lang as string)
|
||||
}}
|
||||
/>
|
||||
<H lvl={2}>{t('preferences.title')}</H>
|
||||
<Field
|
||||
type="switch"
|
||||
label={t('preferences.idleDisconnectModal.label')}
|
||||
description={t('preferences.idleDisconnectModal.description')}
|
||||
isSelected={userPreferencesSnap.is_idle_disconnect_modal_enabled}
|
||||
onChange={(value) =>
|
||||
(userPreferencesStore.is_idle_disconnect_modal_enabled = value)
|
||||
}
|
||||
wrapperProps={{
|
||||
noMargin: true,
|
||||
fullWidth: true,
|
||||
}}
|
||||
/>
|
||||
</TabPanel>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"authentication": "Authentifizierung",
|
||||
"nameError": "Ihr Name darf nicht leer sein"
|
||||
},
|
||||
"preferences": {
|
||||
"title": "Einstellungen",
|
||||
"idleDisconnectModal": {
|
||||
"label": "Anrufe ohne Teilnehmer verlassen",
|
||||
"description": "Verlässt automatisch einen Anruf nach einigen Minuten, wenn kein anderer Teilnehmer beitritt"
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"microphone": {
|
||||
"heading": "Mikrofon",
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"authentication": "Authentication",
|
||||
"nameError": "Your name cannot be empty"
|
||||
},
|
||||
"preferences": {
|
||||
"title": "Preferences",
|
||||
"idleDisconnectModal": {
|
||||
"label": "Leave calls with no participants",
|
||||
"description": "Automatically leaves a call after a few minutes if no other participant joins"
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"microphone": {
|
||||
"heading": "Microphone",
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"authentication": "Authentification",
|
||||
"nameError": "Votre Nom ne peut pas être vide"
|
||||
},
|
||||
"preferences": {
|
||||
"title": "Préférences",
|
||||
"idleDisconnectModal": {
|
||||
"label": "Quitter les appels sans autre participant",
|
||||
"description": "Vous fait quitter un appel au bout de quelques minutes si aucun autre participant ne vous rejoint"
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"microphone": {
|
||||
"heading": "Micro",
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"authentication": "Authenticatie",
|
||||
"nameError": "Uw naam mag niet leeg zijn"
|
||||
},
|
||||
"preferences": {
|
||||
"title": "Voorkeuren",
|
||||
"idleDisconnectModal": {
|
||||
"label": "Verlaat oproepen zonder deelnemers",
|
||||
"description": "Verlaat automatisch een oproep na een paar minuten als geen andere deelnemer meedoet"
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"microphone": {
|
||||
"heading": "Microfoon",
|
||||
|
||||
9
src/frontend/src/stores/userPreferences.ts
Normal file
9
src/frontend/src/stores/userPreferences.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
type State = {
|
||||
is_idle_disconnect_modal_enabled: boolean
|
||||
}
|
||||
|
||||
export const userPreferencesStore = proxy<State>({
|
||||
is_idle_disconnect_modal_enabled: true,
|
||||
})
|
||||
Reference in New Issue
Block a user