Page MenuHomePhabricator

No OneTemporary

diff --git a/native/profile/profile-screen.react.js b/native/profile/profile-screen.react.js
index d7dfa3c72..d2d798a65 100644
--- a/native/profile/profile-screen.react.js
+++ b/native/profile/profile-screen.react.js
@@ -1,626 +1,631 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import { View, Text, Platform, ScrollView } from 'react-native';
import uuid from 'uuid';
import {
logOutActionTypes,
useLogOut,
usePrimaryDeviceLogOut,
useSecondaryDeviceLogOut,
} from 'lib/actions/user-actions.js';
import { useStringForUser } from 'lib/hooks/ens-cache.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import { getOwnPrimaryDeviceID } from 'lib/selectors/user-selectors.js';
import { accountHasPassword } from 'lib/shared/account-utils.js';
import {
type OutboundDMOperationSpecification,
dmOperationSpecificationTypes,
} from 'lib/shared/dm-ops/dm-op-utils.js';
import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
import type { LogOutResult } from 'lib/types/account-types.js';
import type { DMCreateThreadOperation } from 'lib/types/dm-ops';
import { thickThreadTypes } from 'lib/types/thread-types-enum.js';
import { type CurrentUserInfo } from 'lib/types/user-types.js';
import { getContentSigningKey } from 'lib/utils/crypto-utils.js';
import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js';
import {
useDispatchActionPromise,
type DispatchActionPromise,
} from 'lib/utils/redux-promise-utils.js';
import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
import { deleteNativeCredentialsFor } from '../account/native-credentials.js';
import EditUserAvatar from '../avatars/edit-user-avatar.react.js';
import Action from '../components/action-row.react.js';
import Button from '../components/button.react.js';
import EditSettingButton from '../components/edit-setting-button.react.js';
import SingleLine from '../components/single-line.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import {
EditPasswordRouteName,
DeleteAccountRouteName,
BuildInfoRouteName,
DevToolsRouteName,
AppearancePreferencesRouteName,
FriendListRouteName,
BlockListRouteName,
PrivacyPreferencesRouteName,
DefaultNotificationsPreferencesRouteName,
LinkedDevicesRouteName,
BackupMenuRouteName,
KeyserverSelectionListRouteName,
TunnelbrokerMenuRouteName,
FarcasterAccountSettingsRouteName,
} from '../navigation/route-names.js';
import { useSelector } from '../redux/redux-utils.js';
import { type Colors, useColors, useStyles } from '../themes/colors.js';
import Alert from '../utils/alert.js';
+import { useShowVersionUnsupportedAlert } from '../utils/hooks.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
type ProfileRowProps = {
+content: string,
+onPress: () => void,
+danger?: boolean,
};
function ProfileRow(props: ProfileRowProps): React.Node {
const { content, onPress, danger } = props;
return (
<Action.Row onPress={onPress}>
<Action.Text danger={danger} content={content} />
<Action.Icon name="ios-arrow-forward" />
</Action.Row>
);
}
const unboundStyles = {
avatarSection: {
alignItems: 'center',
paddingVertical: 16,
},
container: {
flex: 1,
},
content: {
flex: 1,
},
deleteAccountButton: {
paddingHorizontal: 24,
paddingVertical: 12,
},
editPasswordButton: {
paddingTop: Platform.OS === 'android' ? 3 : 2,
},
header: {
color: 'panelBackgroundLabel',
fontSize: 12,
fontWeight: '400',
paddingBottom: 3,
paddingHorizontal: 24,
},
label: {
color: 'panelForegroundTertiaryLabel',
fontSize: 16,
paddingRight: 12,
},
loggedInLabel: {
color: 'panelForegroundTertiaryLabel',
fontSize: 16,
},
logOutText: {
color: 'link',
fontSize: 16,
paddingLeft: 6,
},
row: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
},
scrollView: {
backgroundColor: 'panelBackground',
},
scrollViewContentContainer: {
paddingTop: 24,
},
paddedRow: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 24,
paddingVertical: 10,
},
section: {
backgroundColor: 'panelForeground',
borderBottomWidth: 1,
borderColor: 'panelForegroundBorder',
borderTopWidth: 1,
marginBottom: 24,
paddingVertical: 1,
},
unpaddedSection: {
backgroundColor: 'panelForeground',
borderBottomWidth: 1,
borderColor: 'panelForegroundBorder',
borderTopWidth: 1,
marginBottom: 24,
},
username: {
color: 'panelForegroundLabel',
flex: 1,
},
value: {
color: 'panelForegroundLabel',
fontSize: 16,
textAlign: 'right',
},
};
type BaseProps = {
+navigation: ProfileNavigationProp<'ProfileScreen'>,
+route: NavigationRoute<'ProfileScreen'>,
};
type Props = {
...BaseProps,
+currentUserInfo: ?CurrentUserInfo,
+primaryDeviceID: ?string,
+logOutLoading: boolean,
+colors: Colors,
+styles: $ReadOnly<typeof unboundStyles>,
+dispatchActionPromise: DispatchActionPromise,
+logOut: () => Promise<LogOutResult>,
+logOutPrimaryDevice: () => Promise<LogOutResult>,
+logOutSecondaryDevice: () => Promise<LogOutResult>,
+staffCanSee: boolean,
+stringForUser: ?string,
+isAccountWithPassword: boolean,
+onCreateDMThread: () => Promise<void>,
+currentUserFID: ?string,
};
class ProfileScreen extends React.PureComponent<Props> {
get loggedOutOrLoggingOut(): boolean {
return (
!this.props.currentUserInfo ||
this.props.currentUserInfo.anonymous ||
this.props.logOutLoading
);
}
render(): React.Node {
let developerTools,
defaultNotifications,
keyserverSelection,
tunnelbrokerMenu;
const { staffCanSee } = this.props;
if (staffCanSee) {
developerTools = (
<ProfileRow content="Developer tools" onPress={this.onPressDevTools} />
);
defaultNotifications = (
<ProfileRow
content="Default Notifications"
onPress={this.onPressDefaultNotifications}
/>
);
keyserverSelection = (
<ProfileRow
content="Keyservers"
onPress={this.onPressKeyserverSelection}
/>
);
tunnelbrokerMenu = (
<ProfileRow
content="Tunnelbroker menu"
onPress={this.onPressTunnelbrokerMenu}
/>
);
}
let backupMenu;
if (staffCanSee) {
backupMenu = (
<ProfileRow content="Backup menu" onPress={this.onPressBackupMenu} />
);
}
let passwordEditionUI;
if (accountHasPassword(this.props.currentUserInfo)) {
passwordEditionUI = (
<Action.Row>
<Text style={this.props.styles.label}>Password</Text>
<Text
style={[this.props.styles.content, this.props.styles.value]}
numberOfLines={1}
>
••••••••••••••••
</Text>
<EditSettingButton
onPress={this.onPressEditPassword}
canChangeSettings={true}
style={this.props.styles.editPasswordButton}
/>
</Action.Row>
);
}
let linkedDevices;
if (__DEV__) {
linkedDevices = (
<ProfileRow content="Linked devices" onPress={this.onPressDevices} />
);
}
let farcasterAccountSettings;
if (usingCommServicesAccessToken || __DEV__) {
farcasterAccountSettings = (
<ProfileRow
content="Farcaster account"
onPress={this.onPressFaracsterAccount}
/>
);
}
let experimentalLogoutActions;
if (__DEV__) {
experimentalLogoutActions = (
<>
<ProfileRow
danger
content="Log out (new flow)"
onPress={this.onPressNewLogout}
/>
</>
);
}
let dmActions;
if (staffCanSee) {
dmActions = (
<>
<ProfileRow
content="Create a new local DM thread"
onPress={this.onPressCreateThread}
/>
</>
);
}
return (
<View style={this.props.styles.container}>
<ScrollView
contentContainerStyle={this.props.styles.scrollViewContentContainer}
style={this.props.styles.scrollView}
>
<Text style={this.props.styles.header}>USER AVATAR</Text>
<View
style={[this.props.styles.section, this.props.styles.avatarSection]}
>
<EditUserAvatar
userID={this.props.currentUserInfo?.id}
fid={this.props.currentUserFID}
/>
</View>
<Text style={this.props.styles.header}>ACCOUNT</Text>
<View style={this.props.styles.section}>
<Action.Row>
<Text style={this.props.styles.loggedInLabel}>Logged in as </Text>
<SingleLine
style={[this.props.styles.label, this.props.styles.username]}
>
{this.props.stringForUser}
</SingleLine>
<Button
onPress={this.onPressLogOut}
disabled={this.loggedOutOrLoggingOut}
>
<Text style={this.props.styles.logOutText}>Log out</Text>
</Button>
</Action.Row>
{passwordEditionUI}
</View>
<View style={this.props.styles.section}>
<ProfileRow
content="Friend list"
onPress={this.onPressFriendList}
/>
<ProfileRow content="Block list" onPress={this.onPressBlockList} />
</View>
<Text style={this.props.styles.header}>PREFERENCES</Text>
<View style={this.props.styles.section}>
<ProfileRow content="Appearance" onPress={this.onPressAppearance} />
<ProfileRow content="Privacy" onPress={this.onPressPrivacy} />
{defaultNotifications}
{backupMenu}
{tunnelbrokerMenu}
</View>
<View style={this.props.styles.section}>
{farcasterAccountSettings}
{linkedDevices}
{keyserverSelection}
<ProfileRow content="Build info" onPress={this.onPressBuildInfo} />
{developerTools}
{experimentalLogoutActions}
{dmActions}
</View>
<View style={this.props.styles.unpaddedSection}>
<ProfileRow
content="Delete account..."
danger
onPress={this.onPressDeleteAccount}
/>
</View>
</ScrollView>
</View>
);
}
onPressLogOut = () => {
if (this.loggedOutOrLoggingOut) {
return;
}
if (!this.props.isAccountWithPassword) {
Alert.alert(
'Log out',
'Are you sure you want to log out?',
[
{ text: 'No', style: 'cancel' },
{
text: 'Yes',
onPress: this.logOutWithoutDeletingNativeCredentialsWrapper,
style: 'destructive',
},
],
{ cancelable: true },
);
return;
}
const alertTitle =
Platform.OS === 'ios' ? 'Keep Login Info in Keychain' : 'Keep Login Info';
const alertDescription =
'We will automatically fill out log-in forms with your credentials ' +
'in the app.';
Alert.alert(
alertTitle,
alertDescription,
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Keep',
onPress: this.logOutWithoutDeletingNativeCredentialsWrapper,
},
{
text: 'Remove',
onPress: this.logOutAndDeleteNativeCredentialsWrapper,
style: 'destructive',
},
],
{ cancelable: true },
);
};
onPressNewLogout = () => {
void (async () => {
if (this.loggedOutOrLoggingOut) {
return;
}
const { primaryDeviceID } = this.props;
const currentDeviceID = await getContentSigningKey();
const isPrimaryDevice = currentDeviceID === primaryDeviceID;
let alertTitle, alertMessage, onPressAction;
if (isPrimaryDevice) {
alertTitle = 'Log out all devices?';
alertMessage =
'This device is your primary device, ' +
'so logging out will cause all of your other devices to log out too.';
onPressAction = this.logOutPrimaryDevice;
} else {
alertTitle = 'Log out?';
alertMessage = 'Are you sure you want to log out of this device?';
onPressAction = this.logOutSecondaryDevice;
}
Alert.alert(
alertTitle,
alertMessage,
[
{ text: 'No', style: 'cancel' },
{
text: 'Yes',
onPress: onPressAction,
style: 'destructive',
},
],
{ cancelable: true },
);
})();
};
logOutWithoutDeletingNativeCredentialsWrapper = () => {
if (this.loggedOutOrLoggingOut) {
return;
}
this.logOut();
};
logOutAndDeleteNativeCredentialsWrapper = async () => {
if (this.loggedOutOrLoggingOut) {
return;
}
await this.deleteNativeCredentials();
this.logOut();
};
logOut() {
void this.props.dispatchActionPromise(
logOutActionTypes,
this.props.logOut(),
);
}
logOutPrimaryDevice = async () => {
if (this.loggedOutOrLoggingOut) {
return;
}
void this.props.dispatchActionPromise(
logOutActionTypes,
this.props.logOutPrimaryDevice(),
);
};
logOutSecondaryDevice = async () => {
if (this.loggedOutOrLoggingOut) {
return;
}
void this.props.dispatchActionPromise(
logOutActionTypes,
this.props.logOutSecondaryDevice(),
);
};
async deleteNativeCredentials() {
await deleteNativeCredentialsFor();
}
onPressEditPassword = () => {
this.props.navigation.navigate({ name: EditPasswordRouteName });
};
onPressDeleteAccount = () => {
this.props.navigation.navigate({ name: DeleteAccountRouteName });
};
onPressFaracsterAccount = () => {
this.props.navigation.navigate({ name: FarcasterAccountSettingsRouteName });
};
onPressDevices = () => {
this.props.navigation.navigate({ name: LinkedDevicesRouteName });
};
onPressBuildInfo = () => {
this.props.navigation.navigate({ name: BuildInfoRouteName });
};
onPressDevTools = () => {
this.props.navigation.navigate({ name: DevToolsRouteName });
};
onPressAppearance = () => {
this.props.navigation.navigate({ name: AppearancePreferencesRouteName });
};
onPressPrivacy = () => {
this.props.navigation.navigate({ name: PrivacyPreferencesRouteName });
};
onPressDefaultNotifications = () => {
this.props.navigation.navigate({
name: DefaultNotificationsPreferencesRouteName,
});
};
onPressFriendList = () => {
this.props.navigation.navigate({ name: FriendListRouteName });
};
onPressBlockList = () => {
this.props.navigation.navigate({ name: BlockListRouteName });
};
onPressBackupMenu = () => {
this.props.navigation.navigate({ name: BackupMenuRouteName });
};
onPressTunnelbrokerMenu = () => {
this.props.navigation.navigate({ name: TunnelbrokerMenuRouteName });
};
onPressKeyserverSelection = () => {
this.props.navigation.navigate({ name: KeyserverSelectionListRouteName });
};
onPressCreateThread = () => {
void this.props.onCreateDMThread();
};
}
const logOutLoadingStatusSelector =
createLoadingStatusSelector(logOutActionTypes);
const ConnectedProfileScreen: React.ComponentType<BaseProps> =
React.memo<BaseProps>(function ConnectedProfileScreen(props: BaseProps) {
const currentUserInfo = useSelector(state => state.currentUserInfo);
const primaryDeviceID = useSelector(getOwnPrimaryDeviceID);
const logOutLoading =
useSelector(logOutLoadingStatusSelector) === 'loading';
const colors = useColors();
const styles = useStyles(unboundStyles);
- const callLogOut = useLogOut();
const callPrimaryDeviceLogOut = usePrimaryDeviceLogOut();
const callSecondaryDeviceLogOut = useSecondaryDeviceLogOut();
const dispatchActionPromise = useDispatchActionPromise();
const staffCanSee = useStaffCanSee();
const stringForUser = useStringForUser(currentUserInfo);
const isAccountWithPassword = useSelector(state =>
accountHasPassword(state.currentUserInfo),
);
const currentUserID = useCurrentUserFID();
+ const showVersionUnsupportedAlert = useShowVersionUnsupportedAlert(false);
+ const callLogOut = useLogOut({
+ handleUseNewFlowResponse: showVersionUnsupportedAlert,
+ });
+
const userID = useSelector(
state => state.currentUserInfo && state.currentUserInfo.id,
);
const processAndSendDMOperation = useProcessAndSendDMOperation();
const onCreateDMThread = React.useCallback(async () => {
invariant(userID, 'userID should be set');
const op: DMCreateThreadOperation = {
type: 'create_thread',
threadID: uuid.v4(),
creatorID: userID,
time: Date.now(),
threadType: thickThreadTypes.LOCAL,
memberIDs: [],
roleID: uuid.v4(),
newMessageID: uuid.v4(),
};
const specification: OutboundDMOperationSpecification = {
type: dmOperationSpecificationTypes.OUTBOUND,
op,
recipients: {
type: 'self_devices',
},
};
await processAndSendDMOperation(specification);
}, [processAndSendDMOperation, userID]);
return (
<ProfileScreen
{...props}
currentUserInfo={currentUserInfo}
primaryDeviceID={primaryDeviceID}
logOutLoading={logOutLoading}
colors={colors}
styles={styles}
logOut={callLogOut}
logOutPrimaryDevice={callPrimaryDeviceLogOut}
logOutSecondaryDevice={callSecondaryDeviceLogOut}
dispatchActionPromise={dispatchActionPromise}
staffCanSee={staffCanSee}
stringForUser={stringForUser}
isAccountWithPassword={isAccountWithPassword}
onCreateDMThread={onCreateDMThread}
currentUserFID={currentUserID}
/>
);
});
export default ConnectedProfileScreen;
diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js
index 460a9e4aa..28abe8225 100644
--- a/web/settings/account-settings.react.js
+++ b/web/settings/account-settings.react.js
@@ -1,356 +1,365 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import uuid from 'uuid';
import {
useLogOut,
logOutActionTypes,
useSecondaryDeviceLogOut,
} from 'lib/actions/user-actions.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/swmansion-icon.react.js';
import { useStringForUser } from 'lib/hooks/ens-cache.js';
import { accountHasPassword } from 'lib/shared/account-utils.js';
import {
dmOperationSpecificationTypes,
type OutboundDMOperationSpecification,
} from 'lib/shared/dm-ops/dm-op-utils.js';
import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import type { DMCreateThreadOperation } from 'lib/types/dm-ops.js';
import { thickThreadTypes } from 'lib/types/thread-types-enum.js';
import {
createOlmSessionsWithOwnDevices,
getContentSigningKey,
} from 'lib/utils/crypto-utils.js';
import { isDev } from 'lib/utils/dev-utils.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import css from './account-settings.css';
import AppearanceChangeModal from './appearance-change-modal.react.js';
import BackupTestRestoreModal from './backup-test-restore-modal.react.js';
import PasswordChangeModal from './password-change-modal.js';
import BlockListModal from './relationship/block-list-modal.react.js';
import FriendListModal from './relationship/friend-list-modal.react.js';
import TunnelbrokerMessagesScreen from './tunnelbroker-message-list.react.js';
import TunnelbrokerTestScreen from './tunnelbroker-test.react.js';
import EditUserAvatar from '../avatars/edit-user-avatar.react.js';
import Button from '../components/button.react.js';
+import VersionUnsupportedModal from '../modals/version-unsupported-modal.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
function AccountSettings(): React.Node {
- const sendLogoutRequest = useLogOut();
+ const { pushModal, popModal } = useModalContext();
+
+ const logOutOptions = React.useMemo(() => {
+ const showVersionUnsupportedModal = () => {
+ pushModal(<VersionUnsupportedModal />);
+ };
+ return { handleUseNewFlowResponse: showVersionUnsupportedModal };
+ }, [pushModal]);
+ const sendLogoutRequest = useLogOut(logOutOptions);
+
const sendSecondaryDeviceLogoutRequest = useSecondaryDeviceLogOut();
const dispatchActionPromise = useDispatchActionPromise();
const logOutUser = React.useCallback(
() => dispatchActionPromise(logOutActionTypes, sendLogoutRequest()),
[dispatchActionPromise, sendLogoutRequest],
);
const logOutSecondaryDevice = React.useCallback(
() =>
dispatchActionPromise(
logOutActionTypes,
sendSecondaryDeviceLogoutRequest(),
),
[dispatchActionPromise, sendSecondaryDeviceLogoutRequest],
);
const identityContext = React.useContext(IdentityClientContext);
const userID = useSelector(state => state.currentUserInfo?.id);
const [deviceID, setDeviceID] = React.useState<?string>();
React.useEffect(() => {
void (async () => {
const contentSigningKey = await getContentSigningKey();
setDeviceID(contentSigningKey);
})();
}, []);
- const { pushModal, popModal } = useModalContext();
const showPasswordChangeModal = React.useCallback(
() => pushModal(<PasswordChangeModal />),
[pushModal],
);
const openFriendList = React.useCallback(
() => pushModal(<FriendListModal />),
[pushModal],
);
const openBlockList = React.useCallback(
() => pushModal(<BlockListModal />),
[pushModal],
);
const isAccountWithPassword = useSelector(state =>
accountHasPassword(state.currentUserInfo),
);
const currentUserInfo = useSelector(state => state.currentUserInfo);
const stringForUser = useStringForUser(currentUserInfo);
const staffCanSee = useStaffCanSee();
const { sendMessageToDevice, socketState, addListener, removeListener } =
useTunnelbroker();
const openTunnelbrokerModal = React.useCallback(
() =>
pushModal(
<TunnelbrokerTestScreen
sendMessageToDevice={sendMessageToDevice}
onClose={popModal}
/>,
),
[popModal, pushModal, sendMessageToDevice],
);
const openTunnelbrokerMessagesModal = React.useCallback(
() =>
pushModal(
<TunnelbrokerMessagesScreen
addListener={addListener}
removeListener={removeListener}
onClose={popModal}
/>,
),
[addListener, popModal, pushModal, removeListener],
);
const onCreateOlmSessions = React.useCallback(async () => {
if (!identityContext) {
return;
}
const authMetadata = await identityContext.getAuthMetadata();
try {
await createOlmSessionsWithOwnDevices(
authMetadata,
identityContext.identityClient,
sendMessageToDevice,
);
} catch (e) {
console.log(`Error creating olm sessions with own devices: ${e.message}`);
}
}, [identityContext, sendMessageToDevice]);
const openBackupTestRestoreModal = React.useCallback(
() => pushModal(<BackupTestRestoreModal onClose={popModal} />),
[popModal, pushModal],
);
const processAndSendDMOperation = useProcessAndSendDMOperation();
const onCreateDMThread = React.useCallback(async () => {
invariant(userID, 'userID should be set');
const op: DMCreateThreadOperation = {
type: 'create_thread',
threadID: uuid.v4(),
creatorID: userID,
time: Date.now(),
threadType: thickThreadTypes.LOCAL,
memberIDs: [],
roleID: uuid.v4(),
newMessageID: uuid.v4(),
};
const specification: OutboundDMOperationSpecification = {
type: dmOperationSpecificationTypes.OUTBOUND,
op,
recipients: {
type: 'self_devices',
},
};
await processAndSendDMOperation(specification);
}, [processAndSendDMOperation, userID]);
const showAppearanceModal = React.useCallback(
() => pushModal(<AppearanceChangeModal />),
[pushModal],
);
if (!currentUserInfo || currentUserInfo.anonymous) {
return null;
}
let changePasswordSection;
if (isAccountWithPassword) {
changePasswordSection = (
<li>
<span>Password</span>
<span className={css.passwordContainer}>
<span className={css.password}>******</span>
<a className={css.editPasswordLink} onClick={showPasswordChangeModal}>
<SWMansionIcon icon="edit-1" size={22} />
</a>
</span>
</li>
);
}
let experimentalLogOutSection;
if (isDev) {
experimentalLogOutSection = (
<li>
<span>Log out secondary device</span>
<Button variant="text" onClick={logOutSecondaryDevice}>
<p className={css.buttonText}>Log out</p>
</Button>
</li>
);
}
let preferences;
if (staffCanSee) {
preferences = (
<div className={css.preferencesContainer}>
<h4 className={css.preferencesHeader}>Preferences</h4>
<div className={css.content}>
<ul>
<li>
<span>Appearance</span>
<a className={css.editPasswordLink} onClick={showAppearanceModal}>
<SWMansionIcon icon="edit-1" size={22} />
</a>
</li>
</ul>
</div>
</div>
);
}
let tunnelbroker;
if (staffCanSee) {
tunnelbroker = (
<div className={css.preferencesContainer}>
<h4 className={css.preferencesHeader}>Tunnelbroker menu</h4>
<div className={css.content}>
<ul>
<li>
<span>Connected</span>
<span>{socketState.connected.toString()}</span>
</li>
<li>
<span>Send message to device</span>
<Button variant="text" onClick={openTunnelbrokerModal}>
<p className={css.buttonText}>Insert data</p>
</Button>
</li>
<li>
<span>Trace received messages</span>
<Button variant="text" onClick={openTunnelbrokerMessagesModal}>
<p className={css.buttonText}>Show list</p>
</Button>
</li>
<li>
<span>Create session with own devices</span>
<Button variant="text" onClick={onCreateOlmSessions}>
<p className={css.buttonText}>Create</p>
</Button>
</li>
</ul>
</div>
</div>
);
}
let backup;
if (staffCanSee) {
backup = (
<div className={css.preferencesContainer}>
<h4 className={css.preferencesHeader}>Backup menu</h4>
<div className={css.content}>
<ul>
<li>
<span>Test backup restore</span>
<Button variant="text" onClick={openBackupTestRestoreModal}>
<p className={css.buttonText}>Insert data</p>
</Button>
</li>
</ul>
</div>
</div>
);
}
let deviceData;
if (staffCanSee) {
deviceData = (
<div className={css.preferencesContainer}>
<h4 className={css.preferencesHeader}>Device ID</h4>
<div className={css.content}>
<ul>
<li>
<span>{deviceID}</span>
</li>
</ul>
</div>
<h4 className={css.preferencesHeader}>User ID</h4>
<div className={css.content}>
<ul>
<li>
<span>{userID}</span>
</li>
</ul>
</div>
</div>
);
}
let dms;
if (staffCanSee) {
dms = (
<div className={css.preferencesContainer}>
<h4 className={css.preferencesHeader}>DMs menu</h4>
<div className={css.content}>
<ul>
<li>
<span>Create a new local DM thread</span>
<Button variant="text" onClick={onCreateDMThread}>
<p className={css.buttonText}>Create</p>
</Button>
</li>
</ul>
</div>
</div>
);
}
return (
<div className={css.container}>
<div className={css.contentContainer}>
<h4 className={css.header}>My Account</h4>
<EditUserAvatar userID={currentUserInfo.id} />
<div className={css.content}>
<ul>
<li>
<p className={css.logoutContainer}>
<span className={css.logoutLabel}>{'Logged in as '}</span>
<span className={css.username}>{stringForUser}</span>
</p>
<Button variant="text" onClick={logOutUser}>
<p className={css.buttonText}>Log out</p>
</Button>
</li>
{experimentalLogOutSection}
{changePasswordSection}
<li>
<span>Friend List</span>
<Button variant="text" onClick={openFriendList}>
<p className={css.buttonText}>See List</p>
</Button>
</li>
<li>
<span>Block List</span>
<Button variant="text" onClick={openBlockList}>
<p className={css.buttonText}>See List</p>
</Button>
</li>
</ul>
</div>
{preferences}
{tunnelbroker}
{backup}
{deviceData}
{dms}
</div>
</div>
);
}
export default AccountSettings;

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 3:04 AM (5 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2690249
Default Alt Text
(30 KB)

Event Timeline