feat: disabled new disappearing message modes behind a timed feature release function

pull/2660/head
William Grant 2 years ago
parent 190c68d759
commit 848c97938c

@ -1,15 +1,41 @@
import React from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { getRightOverlayMode } from '../../../state/selectors/section'; import { getRightOverlayMode } from '../../../state/selectors/section';
import { checkIsFeatureReleased } from '../../../util/releaseFeature';
import { OverlayDisappearingMessages } from './overlay/OverlayDisappearingMessages'; import { OverlayDisappearingMessages } from './overlay/OverlayDisappearingMessages';
import { OverlayRightPanelSettings } from './overlay/OverlayRightPanelSettings'; import { OverlayRightPanelSettings } from './overlay/OverlayRightPanelSettings';
const ClosableOverlay = () => { const ClosableOverlay = () => {
const rightOverlayMode = useSelector(getRightOverlayMode); const rightOverlayMode = useSelector(getRightOverlayMode);
const [showNewDisppearingMessageModes, setShowNewDisppearingMessageModes] = useState(false);
const checkForFeatureRelease = useCallback(async () => {
const isReleased = await checkIsFeatureReleased('Disappearing Messages V2');
return isReleased;
}, []);
useEffect(() => {
let isCancelled = false;
checkForFeatureRelease()
.then(result => {
if (isCancelled) {
return;
}
setShowNewDisppearingMessageModes(result);
})
.catch(() => {
if (isCancelled) return;
});
return () => {
isCancelled = true;
};
}, [checkForFeatureRelease]);
switch (rightOverlayMode) { switch (rightOverlayMode) {
case 'disappearing-messages': case 'disappearing-messages':
return <OverlayDisappearingMessages />; return <OverlayDisappearingMessages unlockAllModes={showNewDisppearingMessageModes} />;
case 'panel-settings': case 'panel-settings':
default: default:
return <OverlayRightPanelSettings />; return <OverlayRightPanelSettings />;

@ -13,6 +13,7 @@ import { PanelRadioButton } from '../../../buttons/PanelRadioButton';
import { SessionIconButton } from '../../../icon'; import { SessionIconButton } from '../../../icon';
import { import {
getSelectedConversationExpirationModes, getSelectedConversationExpirationModes,
getSelectedConversationExpirationModesLocked,
getSelectedConversationExpirationSettings, getSelectedConversationExpirationSettings,
getSelectedConversationKey, getSelectedConversationKey,
} from '../../../../state/selectors/conversations'; } from '../../../../state/selectors/conversations';
@ -98,7 +99,7 @@ const Header = (props: HeaderProps) => {
}; };
type DisappearingModesProps = { type DisappearingModesProps = {
options: Array<DisappearingMessageConversationType>; options: Record<DisappearingMessageConversationType, boolean>;
selected?: DisappearingMessageConversationType; selected?: DisappearingMessageConversationType;
setSelected: (value: string) => void; setSelected: (value: string) => void;
}; };
@ -109,36 +110,37 @@ const DisappearingModes = (props: DisappearingModesProps) => {
<> <>
<PanelLabel>{window.i18n('disappearingMessagesModeLabel')}</PanelLabel> <PanelLabel>{window.i18n('disappearingMessagesModeLabel')}</PanelLabel>
<PanelButtonGroup> <PanelButtonGroup>
{options.map((option: DisappearingMessageConversationType) => { {Object.keys(options).map((mode: DisappearingMessageConversationType) => {
const optionI18n = const optionI18n =
option === 'legacy' mode === 'legacy'
? window.i18n('disappearingMessagesModeLegacy') ? window.i18n('disappearingMessagesModeLegacy')
: option === 'deleteAfterRead' : mode === 'deleteAfterRead'
? window.i18n('disappearingMessagesModeAfterRead') ? window.i18n('disappearingMessagesModeAfterRead')
: option === 'deleteAfterSend' : mode === 'deleteAfterSend'
? window.i18n('disappearingMessagesModeAfterSend') ? window.i18n('disappearingMessagesModeAfterSend')
: window.i18n('disappearingMessagesModeOff'); : window.i18n('disappearingMessagesModeOff');
const subtitleI18n = const subtitleI18n =
option === 'legacy' mode === 'legacy'
? window.i18n('disappearingMessagesModeLegacySubtitle') ? window.i18n('disappearingMessagesModeLegacySubtitle')
: option === 'deleteAfterRead' : mode === 'deleteAfterRead'
? window.i18n('disappearingMessagesModeAfterReadSubtitle') ? window.i18n('disappearingMessagesModeAfterReadSubtitle')
: option === 'deleteAfterSend' : mode === 'deleteAfterSend'
? window.i18n('disappearingMessagesModeAfterSendSubtitle') ? window.i18n('disappearingMessagesModeAfterSendSubtitle')
: undefined; : undefined;
return ( return (
<PanelRadioButton <PanelRadioButton
key={option} key={mode}
text={optionI18n} text={optionI18n}
subtitle={subtitleI18n} subtitle={subtitleI18n}
value={option} value={mode}
isSelected={selected === option} isSelected={selected === mode}
onSelect={() => { onSelect={() => {
setSelected(option); setSelected(mode);
}} }}
disableBg={true} disabled={options[mode]}
noBackgroundColor={true}
/> />
); );
})} })}
@ -173,7 +175,7 @@ const TimeOptions = (props: TimerOptionsProps) => {
onSelect={() => { onSelect={() => {
setSelected(option.value); setSelected(option.value);
}} }}
disableBg={true} noBackgroundColor={true}
/> />
))} ))}
</PanelButtonGroup> </PanelButtonGroup>
@ -181,10 +183,17 @@ const TimeOptions = (props: TimerOptionsProps) => {
); );
}; };
export const OverlayDisappearingMessages = () => { type OverlayDisappearingMessagesProps = { unlockAllModes: boolean };
export const OverlayDisappearingMessages = (props: OverlayDisappearingMessagesProps) => {
const { unlockAllModes } = props;
const dispatch = useDispatch(); const dispatch = useDispatch();
const selectedConversationKey = useSelector(getSelectedConversationKey); const selectedConversationKey = useSelector(getSelectedConversationKey);
const disappearingModeOptions = useSelector(getSelectedConversationExpirationModes); const disappearingModeOptions = useSelector(
unlockAllModes
? getSelectedConversationExpirationModes
: getSelectedConversationExpirationModesLocked
);
const convoProps = useSelector(getSelectedConversationExpirationSettings); const convoProps = useSelector(getSelectedConversationExpirationSettings);

@ -1193,7 +1193,34 @@ export const getSelectedConversationExpirationModes = createSelector(
// Legacy mode is the 2nd option in the UI // Legacy mode is the 2nd option in the UI
modes = [modes[0], modes[modes.length - 1], ...modes.slice(1, modes.length - 1)]; modes = [modes[0], modes[modes.length - 1], ...modes.slice(1, modes.length - 1)];
return modes; const modesWithDisabledState: any = {};
if (modes && modes.length > 1) {
modes.forEach(mode => {
modesWithDisabledState[mode] = false;
});
}
return modesWithDisabledState;
}
);
export const getSelectedConversationExpirationModesLocked = createSelector(
getSelectedConversationExpirationModes,
(modes: any | undefined) => {
const modesWithDisabledState: any = {};
if (modes && Object.keys(modes).length > 1) {
Object.keys(modes).forEach(mode => {
let result = false;
if (mode !== 'legacy') {
result = true;
}
modesWithDisabledState[mode] = result;
});
}
return modesWithDisabledState;
} }
); );

@ -0,0 +1,54 @@
import { Data } from '../data/data';
// TODO update to agreed value between platforms
const featureReleaseTimestamp = 1676851200000; // unix 13/02/2023
// const featureReleaseTimestamp = 1676608378; // test value
let isFeatureReleased: boolean | undefined;
/**
* this is only intended for testing. Do not call this in production.
*/
export function resetFeatureReleasedCachedValue() {
isFeatureReleased = undefined;
}
export async function getIsFeatureReleased(): Promise<boolean> {
if (isFeatureReleased === undefined) {
// read values from db and cache them as it looks like we did not
const oldIsFeatureReleased = (await Data.getItemById('featureReleased'))?.value;
// values do not exist in the db yet. Let's store false for now in the db and update our cached value.
if (oldIsFeatureReleased === undefined) {
await Data.createOrUpdateItem({ id: 'featureReleased', value: false });
isFeatureReleased = false;
} else {
isFeatureReleased = oldIsFeatureReleased;
}
}
return Boolean(isFeatureReleased);
}
export async function checkIsFeatureReleased(featureName: string): Promise<boolean> {
if (isFeatureReleased === undefined) {
const featureAlreadyReleased = await getIsFeatureReleased();
// Is it time to release the feature?
if (Date.now() >= featureReleaseTimestamp) {
if (featureAlreadyReleased) {
// Feature is already released and we don't need to update the db
window.log.info(`WIP: [releaseFeature]: ${featureName} is released`);
} else {
window.log.info(
`WIP: [releaseFeature]: It is time to release ${featureName}. Releasing it now`
);
await Data.createOrUpdateItem({
id: 'featureReleased',
value: true,
});
}
return true;
}
}
window.log.info(`WIP: [releaseFeature]: ${featureName} has not been released yet`);
return false;
}
Loading…
Cancel
Save