show unverified tab indicator on sidebar (#1862)
This commit is contained in:
parent
9cb5c70d51
commit
681287c46a
7 changed files with 123 additions and 33 deletions
|
@ -1,31 +0,0 @@
|
||||||
/* eslint-disable import/prefer-default-export */
|
|
||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useMatrixClient } from './useMatrixClient';
|
|
||||||
|
|
||||||
export function useDeviceList() {
|
|
||||||
const mx = useMatrixClient();
|
|
||||||
const [deviceList, setDeviceList] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let isMounted = true;
|
|
||||||
|
|
||||||
const updateDevices = () => mx.getDevices().then((data) => {
|
|
||||||
if (!isMounted) return;
|
|
||||||
setDeviceList(data.devices || []);
|
|
||||||
});
|
|
||||||
updateDevices();
|
|
||||||
|
|
||||||
const handleDevicesUpdate = (users) => {
|
|
||||||
if (users.includes(mx.getUserId())) {
|
|
||||||
updateDevices();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mx.on('crypto.devicesUpdated', handleDevicesUpdate);
|
|
||||||
return () => {
|
|
||||||
mx.removeListener('crypto.devicesUpdated', handleDevicesUpdate);
|
|
||||||
isMounted = false;
|
|
||||||
};
|
|
||||||
}, [mx]);
|
|
||||||
return deviceList;
|
|
||||||
}
|
|
35
src/app/hooks/useDeviceList.ts
Normal file
35
src/app/hooks/useDeviceList.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* eslint-disable import/prefer-default-export */
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { CryptoEvent, IMyDevice } from 'matrix-js-sdk';
|
||||||
|
import { CryptoEventHandlerMap } from 'matrix-js-sdk/lib/crypto';
|
||||||
|
import { useMatrixClient } from './useMatrixClient';
|
||||||
|
|
||||||
|
export function useDeviceList() {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const [deviceList, setDeviceList] = useState<IMyDevice[] | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
|
||||||
|
const updateDevices = () =>
|
||||||
|
mx.getDevices().then((data) => {
|
||||||
|
if (!isMounted) return;
|
||||||
|
setDeviceList(data.devices || []);
|
||||||
|
});
|
||||||
|
updateDevices();
|
||||||
|
|
||||||
|
const handleDevicesUpdate: CryptoEventHandlerMap[CryptoEvent.DevicesUpdated] = (users) => {
|
||||||
|
const userId = mx.getUserId();
|
||||||
|
if (userId && users.includes(userId)) {
|
||||||
|
updateDevices();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mx.on(CryptoEvent.DevicesUpdated, handleDevicesUpdate);
|
||||||
|
return () => {
|
||||||
|
mx.removeListener(CryptoEvent.DevicesUpdated, handleDevicesUpdate);
|
||||||
|
isMounted = false;
|
||||||
|
};
|
||||||
|
}, [mx]);
|
||||||
|
return deviceList;
|
||||||
|
}
|
|
@ -10,7 +10,15 @@ import {
|
||||||
SidebarItemTooltip,
|
SidebarItemTooltip,
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
} from '../../components/sidebar';
|
} from '../../components/sidebar';
|
||||||
import { DirectTab, HomeTab, SpaceTabs, InboxTab, ExploreTab, UserTab } from './sidebar';
|
import {
|
||||||
|
DirectTab,
|
||||||
|
HomeTab,
|
||||||
|
SpaceTabs,
|
||||||
|
InboxTab,
|
||||||
|
ExploreTab,
|
||||||
|
UserTab,
|
||||||
|
UnverifiedTab,
|
||||||
|
} from './sidebar';
|
||||||
import { openCreateRoom, openSearch } from '../../../client/action/navigation';
|
import { openCreateRoom, openSearch } from '../../../client/action/navigation';
|
||||||
|
|
||||||
export function SidebarNav() {
|
export function SidebarNav() {
|
||||||
|
@ -65,6 +73,8 @@ export function SidebarNav() {
|
||||||
</SidebarItemTooltip>
|
</SidebarItemTooltip>
|
||||||
</SidebarItem>
|
</SidebarItem>
|
||||||
|
|
||||||
|
<UnverifiedTab />
|
||||||
|
|
||||||
<InboxTab />
|
<InboxTab />
|
||||||
<UserTab />
|
<UserTab />
|
||||||
</SidebarStack>
|
</SidebarStack>
|
||||||
|
|
24
src/app/pages/client/sidebar/UnverifiedTab.css.ts
Normal file
24
src/app/pages/client/sidebar/UnverifiedTab.css.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { keyframes, style } from '@vanilla-extract/css';
|
||||||
|
import { color, toRem } from 'folds';
|
||||||
|
|
||||||
|
const pushRight = keyframes({
|
||||||
|
from: {
|
||||||
|
transform: `translateX(${toRem(2)}) scale(1)`,
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
transform: 'translateX(0) scale(1)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UnverifiedTab = style({
|
||||||
|
animationName: pushRight,
|
||||||
|
animationDuration: '400ms',
|
||||||
|
animationIterationCount: 30,
|
||||||
|
animationDirection: 'alternate',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UnverifiedAvatar = style({
|
||||||
|
backgroundColor: color.Critical.Container,
|
||||||
|
color: color.Critical.OnContainer,
|
||||||
|
borderColor: color.Critical.ContainerLine,
|
||||||
|
});
|
51
src/app/pages/client/sidebar/UnverifiedTab.tsx
Normal file
51
src/app/pages/client/sidebar/UnverifiedTab.tsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Badge, color, Icon, Icons, Text } from 'folds';
|
||||||
|
import { openSettings } from '../../../../client/action/navigation';
|
||||||
|
import { isCrossVerified } from '../../../../util/matrixUtil';
|
||||||
|
import {
|
||||||
|
SidebarAvatar,
|
||||||
|
SidebarItem,
|
||||||
|
SidebarItemBadge,
|
||||||
|
SidebarItemTooltip,
|
||||||
|
} from '../../../components/sidebar';
|
||||||
|
import { useDeviceList } from '../../../hooks/useDeviceList';
|
||||||
|
import { tabText } from '../../../organisms/settings/Settings';
|
||||||
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
|
import * as css from './UnverifiedTab.css';
|
||||||
|
|
||||||
|
export function UnverifiedTab() {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const deviceList = useDeviceList();
|
||||||
|
console.log(deviceList);
|
||||||
|
const unverified = deviceList?.filter(
|
||||||
|
(device) => isCrossVerified(mx, device.device_id) === false
|
||||||
|
);
|
||||||
|
console.log(unverified);
|
||||||
|
|
||||||
|
if (!unverified?.length) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem className={css.UnverifiedTab}>
|
||||||
|
<SidebarItemTooltip tooltip="Unverified Sessions">
|
||||||
|
{(triggerRef) => (
|
||||||
|
<SidebarAvatar
|
||||||
|
className={css.UnverifiedAvatar}
|
||||||
|
as="button"
|
||||||
|
ref={triggerRef}
|
||||||
|
outlined
|
||||||
|
onClick={() => openSettings(tabText.SECURITY)}
|
||||||
|
>
|
||||||
|
<Icon style={{ color: color.Critical.Main }} src={Icons.ShieldUser} />
|
||||||
|
</SidebarAvatar>
|
||||||
|
)}
|
||||||
|
</SidebarItemTooltip>
|
||||||
|
<SidebarItemBadge hasCount>
|
||||||
|
<Badge variant="Critical" size="400" fill="Solid" radii="Pill" outlined={false}>
|
||||||
|
<Text as="span" size="L400">
|
||||||
|
{unverified.length}
|
||||||
|
</Text>
|
||||||
|
</Badge>
|
||||||
|
</SidebarItemBadge>
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,3 +4,4 @@ export * from './SpaceTabs';
|
||||||
export * from './InboxTab';
|
export * from './InboxTab';
|
||||||
export * from './ExploreTab';
|
export * from './ExploreTab';
|
||||||
export * from './UserTab';
|
export * from './UserTab';
|
||||||
|
export * from './UnverifiedTab';
|
||||||
|
|
|
@ -106,7 +106,7 @@ export function isCrossVerified(mx, deviceId) {
|
||||||
const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
|
const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
|
||||||
const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
|
const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
|
||||||
return deviceTrust.isCrossSigningVerified();
|
return deviceTrust.isCrossSigningVerified();
|
||||||
} catch {
|
} catch (e) {
|
||||||
// device does not support encryption
|
// device does not support encryption
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue