diff --git a/ts/components/SessionInboxView.tsx b/ts/components/SessionInboxView.tsx index 6d26b5df4..f2d8c7616 100644 --- a/ts/components/SessionInboxView.tsx +++ b/ts/components/SessionInboxView.tsx @@ -1,12 +1,12 @@ +import { fromPairs, map } from 'lodash'; import moment from 'moment'; import React from 'react'; import { Provider } from 'react-redux'; -import styled from 'styled-components'; -import { fromPairs, map } from 'lodash'; +import useMount from 'react-use/lib/useMount'; +import useUpdate from 'react-use/lib/useUpdate'; import { persistStore } from 'redux-persist'; import { PersistGate } from 'redux-persist/integration/react'; -import useUpdate from 'react-use/lib/useUpdate'; -import useMount from 'react-use/lib/useMount'; +import styled from 'styled-components'; import { LeftPane } from './leftpane/LeftPane'; // moment does not support es-419 correctly (and cause white screen on app start) @@ -26,10 +26,8 @@ import { initialSearchState } from '../state/ducks/search'; import { initialSectionState } from '../state/ducks/section'; import { getEmptyStagedAttachmentsState } from '../state/ducks/stagedAttachments'; import { initialThemeState } from '../state/ducks/theme'; -import { TimerOptionsArray } from '../state/ducks/timerOptions'; import { initialUserConfigState } from '../state/ducks/userConfig'; import { StateType } from '../state/reducer'; -import { ExpirationTimerOptions } from '../util/expiringMessages'; import { SessionMainPanel } from './SessionMainPanel'; import { SettingsKey } from '../data/settings-key'; @@ -64,7 +62,6 @@ function createSessionInboxStore() { .getConversations() .map(conversation => conversation.getConversationModelProps()); - const timerOptions: TimerOptionsArray = ExpirationTimerOptions.getTimerSecondsWithName(); const initialState: StateType = { conversations: { ...getEmptyConversationState(), @@ -82,9 +79,6 @@ function createSessionInboxStore() { onionPaths: initialOnionPathState, modals: initialModalState, userConfig: initialUserConfigState, - timerOptions: { - timerOptions, - }, stagedAttachments: getEmptyStagedAttachmentsState(), call: initialCallState, sogsRoomInfo: initialSogsRoomInfoState, diff --git a/ts/components/conversation/right-panel/overlay/disappearing-messages/TimeOptions.tsx b/ts/components/conversation/right-panel/overlay/disappearing-messages/TimeOptions.tsx index bbefb2670..9717486ef 100644 --- a/ts/components/conversation/right-panel/overlay/disappearing-messages/TimeOptions.tsx +++ b/ts/components/conversation/right-panel/overlay/disappearing-messages/TimeOptions.tsx @@ -1,6 +1,6 @@ import { isEmpty } from 'lodash'; import React from 'react'; -import { TimerOptionsArray } from '../../../../../state/ducks/timerOptions'; +import { TimerOptionsArray } from '../../../../../util/expiringMessages'; import { PanelButtonGroup, PanelLabel } from '../../../../buttons/PanelButton'; import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; diff --git a/ts/hooks/useParamSelector.ts b/ts/hooks/useParamSelector.ts index 8a8c8bf53..5cedf308a 100644 --- a/ts/hooks/useParamSelector.ts +++ b/ts/hooks/useParamSelector.ts @@ -1,4 +1,5 @@ import { compact, isEmpty, isFinite, isNumber } from 'lodash'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { hasValidIncomingRequestValues, @@ -9,8 +10,16 @@ import { CONVERSATION } from '../session/constants'; import { PubKey } from '../session/types'; import { UserUtils } from '../session/utils'; import { StateType } from '../state/reducer'; -import { getMessageReactsProps, getMessageExpirationProps } from '../state/selectors/conversations'; +import { getMessageExpirationProps, getMessageReactsProps } from '../state/selectors/conversations'; import { isPrivateAndFriend } from '../state/selectors/selectedConversation'; +import { + DELETE_AFTER_READ_OPTIONS, + DELETE_AFTER_SEND_OPTIONS, + DELETE_LEGACY_OPTIONS, + ExpirationTimerOptions, + TIMER_OPTIONS, + TimerOptionsArray, +} from '../util/expiringMessages'; export function useAvatarPath(convoId: string | undefined) { const convoProps = useConversationPropsById(convoId); @@ -280,63 +289,46 @@ export function useMessageExpirationPropsById(messageId?: string) { }); } -// TODO use env variable to toggle test values? -// https://github.com/oxen-io/session-desktop/pull/2660/files#r1174823750 export function useTimerOptionsByMode(disappearingMessageMode?: string, hasOnlyOneMode?: boolean) { - return useSelector((state: StateType) => { - const options = state.timerOptions.timerOptions; - + return useMemo(() => { + const options: TimerOptionsArray = []; + if (hasOnlyOneMode) { + options.push({ + name: ExpirationTimerOptions.getName(TIMER_OPTIONS[0]), + value: TIMER_OPTIONS[0], + }); + } switch (disappearingMessageMode) { // TODO legacy messages support will be removed in a future release case 'legacy': - return options.filter(option => { - return ( - (hasOnlyOneMode && option.value === 0) || - option.value === 5 || // 5 seconds - option.value === 10 || // 10 seconds - option.value === 30 || // 30 seconds - option.value === 60 || // 1 minute - option.value === 300 || // 5 minutes - option.value === 1800 || // 30 minutes - option.value === 3600 || // 1 hour - option.value === 21600 || // 6 hours - option.value === 43200 || // 12 hours - option.value === 86400 || // 1 day - option.value === 604800 // 1 week - ); - }); - case 'deleteAfterSend': - return options.filter(option => { - return ( - (hasOnlyOneMode && option.value === 0) || - // option.value === 10 || // 10 seconds (for development) - // option.value === 30 || // 30 seconds (for development) - option.value === 60 || // 1 minute (for testing) - option.value === 43200 || // 12 hours - option.value === 86400 || // 1 day - option.value === 604800 || // 1 week - option.value === 1209600 // 2 weeks - ); - }); + options.push( + ...DELETE_LEGACY_OPTIONS.map(option => ({ + name: ExpirationTimerOptions.getName(option), + value: option, + })) + ); + break; case 'deleteAfterRead': - return options.filter(option => { - return ( - (hasOnlyOneMode && option.value === 0) || - // option.value === 10 || // 10 seconds (for development) - // option.value === 30 || // 30 seconds (for development) - option.value === 60 || // 1 minute (for testing) - option.value === 300 || // 5 minutes - option.value === 3600 || // 1 hour - option.value === 43200 || // 12 hours - option.value === 86400 || // 1 day - option.value === 604800 || // 1 week - option.value === 1209600 // 2 weeks - ); - }); + options.push( + ...DELETE_AFTER_READ_OPTIONS.map(option => ({ + name: ExpirationTimerOptions.getName(option), + value: option, + })) + ); + break; + case 'deleteAfterSend': + options.push( + ...DELETE_AFTER_SEND_OPTIONS.map(option => ({ + name: ExpirationTimerOptions.getName(option), + value: option, + })) + ); + break; default: return []; } - }); + return options; + }, [disappearingMessageMode, hasOnlyOneMode]); } export function useQuoteAuthorName( diff --git a/ts/state/ducks/timerOptions.tsx b/ts/state/ducks/timerOptions.tsx deleted file mode 100644 index ca161a53e..000000000 --- a/ts/state/ducks/timerOptions.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This slice is intended for the user configurable settings for the client such as appearance, autoplaying of links etc. - * Anything setting under the cog wheel tab. - */ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -type TimerOptionsEntry = { name: string; value: number }; -export type TimerOptionsArray = Array; - -export type TimerOptionsState = { - timerOptions: TimerOptionsArray; -}; - -export const initialTimerOptionsState: TimerOptionsState = { - timerOptions: [], -}; - -const timerOptionSlice = createSlice({ - name: 'timerOptions', - initialState: initialTimerOptionsState, - reducers: { - updateTimerOptions: (state, action: PayloadAction) => { - return { ...state, timerOptions: action.payload }; - }, - }, -}); - -const { actions, reducer } = timerOptionSlice; -export const { updateTimerOptions } = actions; -export const timerOptionReducer = reducer; diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index c6db627a7..eb382c372 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -1,25 +1,24 @@ import { combineReducers } from '@reduxjs/toolkit'; -import { reducer as search, SearchStateType } from './ducks/search'; -import { ConversationsStateType, reducer as conversations } from './ducks/conversations'; -import { reducer as user, UserStateType } from './ducks/user'; -import { reducer as theme } from './ducks/theme'; +import { callReducer as call, CallStateType } from './ducks/call'; +import { reducer as conversations, ConversationsStateType } from './ducks/conversations'; +import { defaultRoomReducer as defaultRooms, DefaultRoomsState } from './ducks/defaultRooms'; import { reducer as primaryColor } from './ducks/primaryColor'; +import { reducer as search, SearchStateType } from './ducks/search'; import { reducer as section, SectionStateType } from './ducks/section'; -import { defaultRoomReducer as defaultRooms, DefaultRoomsState } from './ducks/defaultRooms'; import { ReduxSogsRoomInfos, SogsRoomInfoState } from './ducks/sogsRoomInfo'; -import { callReducer as call, CallStateType } from './ducks/call'; +import { reducer as theme } from './ducks/theme'; +import { reducer as user, UserStateType } from './ducks/user'; -import { defaultOnionReducer as onionPaths, OnionState } from './ducks/onion'; +import { PrimaryColorStateType, ThemeStateType } from '../themes/constants/colors'; import { modalReducer as modals, ModalState } from './ducks/modalDialog'; -import { userConfigReducer as userConfig, UserConfigState } from './ducks/userConfig'; -import { timerOptionReducer as timerOptions, TimerOptionsState } from './ducks/timerOptions'; +import { defaultOnionReducer as onionPaths, OnionState } from './ducks/onion'; +import { settingsReducer, SettingsState } from './ducks/settings'; import { reducer as stagedAttachments, StagedAttachmentsStateType, } from './ducks/stagedAttachments'; -import { PrimaryColorStateType, ThemeStateType } from '../themes/constants/colors'; -import { settingsReducer, SettingsState } from './ducks/settings'; +import { userConfigReducer as userConfig, UserConfigState } from './ducks/userConfig'; export type StateType = { search: SearchStateType; @@ -32,7 +31,6 @@ export type StateType = { onionPaths: OnionState; modals: ModalState; userConfig: UserConfigState; - timerOptions: TimerOptionsState; stagedAttachments: StagedAttachmentsStateType; call: CallStateType; sogsRoomInfo: SogsRoomInfoState; @@ -50,7 +48,6 @@ export const reducers = { onionPaths, modals, userConfig, - timerOptions, stagedAttachments, call, sogsRoomInfo: ReduxSogsRoomInfos.sogsRoomInfoReducer, diff --git a/ts/state/selectors/index.ts b/ts/state/selectors/index.ts index 304e6986a..f64511879 100644 --- a/ts/state/selectors/index.ts +++ b/ts/state/selectors/index.ts @@ -7,7 +7,6 @@ import * as SearchSelectors from './search'; import * as SectionSelectors from './section'; import * as StagedAttachmentSelectors from './stagedAttachments'; import * as ThemeSelectors from './theme'; -import * as TimerOptionsSelectors from './timerOptions'; import * as UserSelectors from './user'; import * as UserConfigSelectors from './userConfig'; @@ -21,7 +20,6 @@ export { SectionSelectors, StagedAttachmentSelectors, ThemeSelectors, - TimerOptionsSelectors, UserConfigSelectors, UserSelectors, }; diff --git a/ts/state/selectors/timerOptions.ts b/ts/state/selectors/timerOptions.ts deleted file mode 100644 index bda714d5d..000000000 --- a/ts/state/selectors/timerOptions.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { StateType } from '../reducer'; -import { TimerOptionsState } from '../ducks/timerOptions'; - -export const getTimerOptions = (state: StateType): TimerOptionsState => state.timerOptions; diff --git a/ts/util/expiringMessages.ts b/ts/util/expiringMessages.ts index 8585961a6..f658b48f4 100644 --- a/ts/util/expiringMessages.ts +++ b/ts/util/expiringMessages.ts @@ -1,7 +1,6 @@ import { throttle, uniq } from 'lodash'; import moment from 'moment'; import { messagesExpired } from '../state/ducks/conversations'; -import { TimerOptionsArray } from '../state/ducks/timerOptions'; import { LocalizerKeys } from '../types/LocalizerKeys'; import { initWallClockListener } from './wallClockListener'; @@ -31,12 +30,6 @@ export const DisappearingMessageConversationModes = [ ] as const; export type DisappearingMessageConversationModeType = typeof DisappearingMessageConversationModes[number]; // TODO we should make this type a bit more hardcoded than being just resolved as a string -export const DEFAULT_TIMER_OPTION = { - DELETE_AFTER_READ: 43200, // 12 hours - DELETE_AFTER_SEND: 86400, // 1 day - LEGACY: 86400, // 1 day -}; - // TODO legacy messages support will be removed in a future release // expirationType and lastDisappearingMessageChangeTimestamp will no longer have an undefined option /** Used for setting disappearing messages in conversations */ @@ -185,15 +178,7 @@ const updateExpiringMessagesCheck = () => { void throttledCheckExpiringMessages(); }; -function getTimerOptionName(time: number, unit: moment.DurationInputArg2) { - return ( - window.i18n(['timerOption', time, unit].join('_') as LocalizerKeys) || - moment.duration(time, unit).humanize() - ); -} -function getTimerOptionAbbreviated(time: number, unit: string) { - return window.i18n(['timerOption', time, unit, 'abbreviated'].join('_') as LocalizerKeys); -} +// #region Timer Options const timerOptionsDurations: Array<{ time: number; @@ -222,6 +207,17 @@ const timerOptionsDurations: Array<{ }; }); +function getTimerOptionName(time: number, unit: moment.DurationInputArg2) { + return ( + window.i18n(['timerOption', time, unit].join('_') as LocalizerKeys) || + moment.duration(time, unit).humanize() + ); +} + +function getTimerOptionAbbreviated(time: number, unit: string) { + return window.i18n(['timerOption', time, unit, 'abbreviated'].join('_') as LocalizerKeys); +} + function getName(seconds = 0) { const o = timerOptionsDurations.find(m => m.seconds === seconds); @@ -230,6 +226,7 @@ function getName(seconds = 0) { } return [seconds, 'seconds'].join(' '); } + function getAbbreviated(seconds = 0) { const o = timerOptionsDurations.find(m => m.seconds === seconds); @@ -240,20 +237,72 @@ function getAbbreviated(seconds = 0) { return [seconds, 's'].join(''); } -function getTimerSecondsWithName(): TimerOptionsArray { - return timerOptionsDurations.map(t => { - return { name: getName(t.seconds), value: t.seconds }; - }); -} +type TimerOptionsEntry = { name: string; value: number }; +export type TimerOptionsArray = Array; + +export const TIMER_OPTIONS: Array = timerOptionsDurations.map(t => { + return t.seconds; +}); + +export const DELETE_AFTER_READ_OPTIONS = TIMER_OPTIONS.filter(option => { + return ( + option === 10 || // 10 seconds (for development or qa) + option === 30 || // 30 seconds (for development or qa) + option === 60 || // 1 minute (for testing) + option === 300 || // 5 minutes + option === 3600 || // 1 hour + option === 43200 || // 12 hours + option === 86400 || // 1 day + option === 604800 || // 1 week + option === 1209600 // 2 weeks + ); +}); + +export const DELETE_AFTER_SEND_OPTIONS = TIMER_OPTIONS.filter(option => { + return ( + option === 10 || // 10 seconds (for development or qa) + option === 30 || // 30 seconds (for development or qa) + option === 60 || // 1 minute (for testing) + option === 43200 || // 12 hours + option === 86400 || // 1 day + option === 604800 || // 1 week + option === 1209600 // 2 weeks + ); +}); + +// TODO legacy messages support will be removed in a future release +export const DELETE_LEGACY_OPTIONS = TIMER_OPTIONS.filter(option => { + return ( + option === 5 || // 5 seconds + option === 10 || // 10 seconds + option === 30 || // 30 seconds + option === 60 || // 1 minute + option === 300 || // 5 minutes + option === 1800 || // 30 minutes + option === 3600 || // 1 hour + option === 21600 || // 6 hours + option === 43200 || // 12 hours + option === 86400 || // 1 day + option === 604800 // 1 week + ); +}); + +export const DEFAULT_TIMER_OPTION = { + DELETE_AFTER_READ: 43200, // 12 hours + DELETE_AFTER_SEND: 86400, // 1 day + // TODO legacy messages support will be removed in a future release + LEGACY: 86400, // 1 day +}; export const ExpirationTimerOptions = { getName, getAbbreviated, updateExpiringMessagesCheck, initExpiringMessageListener, - getTimerSecondsWithName, }; +// #endregion Timer Options + export function setExpirationStartTimestamp( mode: DisappearingMessageConversationModeType, timestamp?: number,