diff --git a/ts/components/SessionInboxView.tsx b/ts/components/SessionInboxView.tsx index c1e7c5c4d..f1da22b84 100644 --- a/ts/components/SessionInboxView.tsx +++ b/ts/components/SessionInboxView.tsx @@ -41,6 +41,7 @@ import { UserGroupsWrapperActions } from '../webworker/workers/browser/libsessio import { NoticeBanner } from './NoticeBanner'; import { Flex } from './basic/Flex'; import { initialReleasedFeaturesState } from '../state/ducks/releasedFeatures'; +import { initialDebugState } from '../state/ducks/debug'; function makeLookup(items: Array, key: string): { [key: string]: T } { // Yep, we can't index into item without knowing what it is. True. But we want to. @@ -90,6 +91,7 @@ async function createSessionInboxStore() { groups: initialGroupState, userGroups: { userGroups }, releasedFeatures: initialReleasedFeaturesState, + debug: initialDebugState, }; return createStore(initialState); diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 2a3c2e0b8..4cfd49d34 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -54,6 +54,7 @@ import { getIsModalVisible } from '../../state/selectors/modal'; import { ReleasedFeatures } from '../../util/releaseFeature'; import { MessageQueue } from '../../session/sending'; import { useRefreshReleasedFeaturesTimestamp } from '../../hooks/useRefreshReleasedFeaturesTimestamp'; +import { useDebugMode } from '../../state/selectors/debug'; const Section = (props: { type: SectionType }) => { const ourNumber = useSelector(getOurNumber); @@ -259,7 +260,7 @@ function useUpdateBadgeCount() { export const ActionsPanel = () => { const [startCleanUpMedia, setStartCleanUpMedia] = useState(false); const ourPrimaryConversation = useSelector(getOurPrimaryConversation); - const showDebugMenu = window?.sessionFeatureFlags?.debug?.debugLogging; + const showDebugMenu = useDebugMode(); // this maxi useEffect is called only once: when the component is mounted. // For the action panel, it means this is called only one per app start/with a user logged in @@ -322,6 +323,7 @@ export const ActionsPanel = () => { window?.log?.warn('ActionsPanel: ourPrimaryConversation is not set'); return null; } + return ( <> diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index e49151921..aacc61036 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -20,6 +20,7 @@ import { SettingsCategoryHelp } from './section/CategoryHelp'; import { SettingsCategoryPermissions } from './section/CategoryPermissions'; import { SettingsCategoryPrivacy } from './section/CategoryPrivacy'; import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; +import { setDebugMode } from '../../state/ducks/debug'; export function displayPasswordModal( passwordAction: PasswordAction, @@ -68,6 +69,10 @@ const StyledSpanSessionInfo = styled.span` `; const SessionInfo = () => { + const [clickCount, setClickCount] = useState(0); + + const dispatch = useDispatch(); + return ( { }} /> - {window.versionInfo.commitHash} + { + setClickCount(clickCount + 1); + if (clickCount === 10) { + dispatch(setDebugMode(true)); + setClickCount(0); + } + }} + > + {window.versionInfo.commitHash} + ); }; diff --git a/ts/state/ducks/debug.tsx b/ts/state/ducks/debug.tsx new file mode 100644 index 000000000..f263b833b --- /dev/null +++ b/ts/state/ducks/debug.tsx @@ -0,0 +1,24 @@ +import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; + +export interface DebugState { + debugMode: boolean; +} + +export const initialDebugState = { + debugMode: false, +}; + +const debugSlice = createSlice({ + name: 'debug', + initialState: initialDebugState, + reducers: { + setDebugMode: (state, action: PayloadAction) => { + (window as Window).sessionFeatureFlags.debug.debugLogging = action.payload; + return { ...state, debugMode: action.payload }; + }, + }, +}); + +const { actions, reducer } = debugSlice; +export const { setDebugMode } = actions; +export const debugReducer = reducer; diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index 9b6620679..d5f4336d5 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -22,6 +22,7 @@ import { import { userConfigReducer as userConfig, UserConfigState } from './ducks/userConfig'; import { userGroupReducer, UserGroupState } from './ducks/userGroups'; import { releasedFeaturesReducer, ReleasedFeaturesState } from './ducks/releasedFeatures'; +import { debugReducer, type DebugState } from './ducks/debug'; export type StateType = { search: SearchStateType; @@ -41,6 +42,7 @@ export type StateType = { groups: GroupState; userGroups: UserGroupState; releasedFeatures: ReleasedFeaturesState; + debug: DebugState; }; const reducers = { @@ -61,6 +63,7 @@ const reducers = { groups: groupReducer, userGroups: userGroupReducer, releasedFeatures: releasedFeaturesReducer, + debug: debugReducer, }; // Making this work would require that our reducer signature supported AnyAction, not diff --git a/ts/state/selectors/debug.ts b/ts/state/selectors/debug.ts new file mode 100644 index 000000000..7a79d83c0 --- /dev/null +++ b/ts/state/selectors/debug.ts @@ -0,0 +1,10 @@ +import { useSelector } from 'react-redux'; +import type { StateType } from '../reducer'; + +const getDebugMode = (state: StateType): boolean => { + return window.sessionFeatureFlags.debug.debugLogging || state.debug.debugMode; +}; + +export const useDebugMode = (): boolean => { + return useSelector(getDebugMode); +};