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 { getRightOverlayMode } from '../../../state/selectors/section';
import { checkIsFeatureReleased } from '../../../util/releaseFeature';
import { OverlayDisappearingMessages } from './overlay/OverlayDisappearingMessages';
import { OverlayRightPanelSettings } from './overlay/OverlayRightPanelSettings';
const ClosableOverlay = () => {
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) {
case 'disappearing-messages':
return <OverlayDisappearingMessages />;
return <OverlayDisappearingMessages unlockAllModes={showNewDisppearingMessageModes} />;
case 'panel-settings':
default:
return <OverlayRightPanelSettings />;

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

@ -1193,7 +1193,34 @@ export const getSelectedConversationExpirationModes = createSelector(
// Legacy mode is the 2nd option in the UI
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