mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 14:30:29 +03:00 
			
		
		
		
	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,
 | 
			
		||||
  SidebarItem,
 | 
			
		||||
} 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';
 | 
			
		||||
 | 
			
		||||
export function SidebarNav() {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +73,8 @@ export function SidebarNav() {
 | 
			
		|||
                </SidebarItemTooltip>
 | 
			
		||||
              </SidebarItem>
 | 
			
		||||
 | 
			
		||||
              <UnverifiedTab />
 | 
			
		||||
 | 
			
		||||
              <InboxTab />
 | 
			
		||||
              <UserTab />
 | 
			
		||||
            </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 './ExploreTab';
 | 
			
		||||
export * from './UserTab';
 | 
			
		||||
export * from './UnverifiedTab';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ export function isCrossVerified(mx, deviceId) {
 | 
			
		|||
    const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
 | 
			
		||||
    const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
 | 
			
		||||
    return deviceTrust.isCrossSigningVerified();
 | 
			
		||||
  } catch {
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    // device does not support encryption
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue