mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-02-07 14:23:38 +01:00
add device verification status badge
This commit is contained in:
parent
64d80a8684
commit
dff90a1ae0
5 changed files with 104 additions and 16 deletions
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Text, IconButton, Icon, Icons, Scroll, Button } from 'folds';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
|
@ -9,9 +9,10 @@ import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
|||
import { LocalBackup } from './LocalBackup';
|
||||
import { DeviceLogoutBtn, DeviceTile, DeviceTilePlaceholder } from './DeviceTile';
|
||||
import { OtherDevices } from './OtherDevices';
|
||||
import { ManualVerificationTile } from './Verificaton';
|
||||
import { ManualVerificationTile, VerificationStatusBadge } from './Verificaton';
|
||||
import {
|
||||
useDeviceVerificationStatus,
|
||||
useUnverifiedDeviceCount,
|
||||
VerificationStatus,
|
||||
} from '../../../hooks/useDeviceVerificationStatus';
|
||||
|
||||
|
@ -43,6 +44,16 @@ export function Devices({ requestClose }: DevicesProps) {
|
|||
currentDevice?.device_id
|
||||
);
|
||||
|
||||
const otherDevicesId = useMemo(
|
||||
() => otherDevices?.map((device) => device.device_id) ?? [],
|
||||
[otherDevices]
|
||||
);
|
||||
const unverifiedDeviceCount = useUnverifiedDeviceCount(
|
||||
crypto,
|
||||
mx.getSafeUserId(),
|
||||
otherDevicesId
|
||||
);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader outlined={false}>
|
||||
|
@ -75,11 +86,18 @@ export function Devices({ requestClose }: DevicesProps) {
|
|||
title="Device Verification"
|
||||
description="To verify your identity and grant access to your encrypted messages on another device."
|
||||
after={
|
||||
<Button size="300" radii="300">
|
||||
<Text as="span" size="B300">
|
||||
Activate
|
||||
</Text>
|
||||
</Button>
|
||||
true ? (
|
||||
<VerificationStatusBadge
|
||||
verificationStatus={verificationStatus}
|
||||
otherUnverifiedCount={unverifiedDeviceCount}
|
||||
/>
|
||||
) : (
|
||||
<Button size="300" radii="300">
|
||||
<Text as="span" size="B300">
|
||||
Activate
|
||||
</Text>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</SequenceCard>
|
||||
|
@ -111,7 +129,7 @@ export function Devices({ requestClose }: DevicesProps) {
|
|||
<OtherDevices
|
||||
devices={otherDevices}
|
||||
refreshDeviceList={refreshDeviceList}
|
||||
verified={verificationStatus === VerificationStatus.Verified}
|
||||
showVerification={verificationStatus === VerificationStatus.Verified}
|
||||
/>
|
||||
)}
|
||||
<LocalBackup />
|
||||
|
|
|
@ -15,9 +15,9 @@ import { VerificationStatus } from '../../../hooks/useDeviceVerificationStatus';
|
|||
type OtherDevicesProps = {
|
||||
devices: IMyDevice[];
|
||||
refreshDeviceList: () => Promise<void>;
|
||||
verified?: boolean;
|
||||
showVerification?: boolean;
|
||||
};
|
||||
export function OtherDevices({ devices, refreshDeviceList, verified }: OtherDevicesProps) {
|
||||
export function OtherDevices({ devices, refreshDeviceList, showVerification }: OtherDevicesProps) {
|
||||
const mx = useMatrixClient();
|
||||
const crypto = mx.getCrypto();
|
||||
const [deleted, setDeleted] = useState<Set<string>>(new Set());
|
||||
|
@ -97,7 +97,7 @@ export function OtherDevices({ devices, refreshDeviceList, verified }: OtherDevi
|
|||
/>
|
||||
}
|
||||
/>
|
||||
{verified && (
|
||||
{showVerification && (
|
||||
<DeviceVerificationStatus
|
||||
crypto={crypto}
|
||||
userId={mx.getSafeUserId()}
|
||||
|
|
|
@ -1,7 +1,42 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Box, Button, config, Text } from 'folds';
|
||||
import { Badge, Box, Button, config, Spinner, Text } from 'folds';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
import * as css from './style.css';
|
||||
import { VerificationStatus } from '../../../hooks/useDeviceVerificationStatus';
|
||||
|
||||
type VerificationStatusBadgeProps = {
|
||||
verificationStatus: VerificationStatus;
|
||||
otherUnverifiedCount?: number;
|
||||
};
|
||||
export function VerificationStatusBadge({
|
||||
verificationStatus,
|
||||
otherUnverifiedCount,
|
||||
}: VerificationStatusBadgeProps) {
|
||||
if (verificationStatus === VerificationStatus.Unknown || !otherUnverifiedCount) {
|
||||
return <Spinner size="400" variant="Secondary" />;
|
||||
}
|
||||
if (verificationStatus === VerificationStatus.Unverified) {
|
||||
return (
|
||||
<Badge variant="Critical" fill="Solid" size="500">
|
||||
<Text size="L400">Unverified</Text>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
if (otherUnverifiedCount > 0) {
|
||||
return (
|
||||
<Badge variant="Critical" fill="Solid" size="500">
|
||||
<Text size="L400">{otherUnverifiedCount} Unverified</Text>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Badge variant="Success" fill="Solid" size="500">
|
||||
<Text size="L400">Verified</Text>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
function LearnStartVerificationFromOtherDevice() {
|
||||
return (
|
||||
|
@ -39,7 +74,7 @@ export function ManualVerificationTile() {
|
|||
<div className={css.UnverifiedCard}>
|
||||
<SettingTile
|
||||
after={
|
||||
<Button size="300" variant="Warning" fill="Soft" radii="300">
|
||||
<Button size="300" variant="Critical" fill="Soft" radii="300">
|
||||
<Text size="B300">Verify Manually</Text>
|
||||
</Button>
|
||||
}
|
||||
|
@ -62,7 +97,7 @@ export function StartVerificationTile() {
|
|||
<div className={css.UnverifiedCard}>
|
||||
<SettingTile
|
||||
after={
|
||||
<Button size="300" variant="Warning" radii="300">
|
||||
<Button size="300" variant="Critical" radii="300">
|
||||
<Text size="B300">Start Verification</Text>
|
||||
</Button>
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { config } from 'folds';
|
|||
import { ContainerColor } from '../../../styles/ContainerColor.css';
|
||||
|
||||
export const UnverifiedCard = style([
|
||||
ContainerColor({ variant: 'Warning' }),
|
||||
ContainerColor({ variant: 'Critical' }),
|
||||
{
|
||||
padding: config.space.S200,
|
||||
borderRadius: config.radii.R300,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CryptoApi } from 'matrix-js-sdk/lib/crypto-api';
|
||||
import { AsyncStatus, useAsyncCallback } from './useAsyncCallback';
|
||||
import { verifiedDevice } from '../utils/matrix-crypto';
|
||||
import { useAlive } from './useAlive';
|
||||
import { fulfilledPromiseSettledResult } from '../utils/common';
|
||||
|
||||
export enum VerificationStatus {
|
||||
Unknown,
|
||||
|
@ -29,3 +31,36 @@ export const useDeviceVerificationStatus = (
|
|||
|
||||
return VerificationStatus.Unknown;
|
||||
};
|
||||
|
||||
export const useUnverifiedDeviceCount = (
|
||||
crypto: CryptoApi | undefined,
|
||||
userId: string,
|
||||
devices: string[]
|
||||
): number | undefined => {
|
||||
const [unverifiedCount, setUnverifiedCount] = useState<number>();
|
||||
const alive = useAlive();
|
||||
|
||||
useEffect(() => {
|
||||
const findCount = async () => {
|
||||
if (crypto) {
|
||||
const promises = devices.map((deviceId) => verifiedDevice(crypto, userId, deviceId));
|
||||
const result = await Promise.allSettled(promises);
|
||||
const settledResult = fulfilledPromiseSettledResult(result);
|
||||
return settledResult.reduce((count, status) => {
|
||||
if (status === false) {
|
||||
return count + 1;
|
||||
}
|
||||
return count;
|
||||
}, 0);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
findCount().then((count) => {
|
||||
if (alive()) {
|
||||
setUnverifiedCount(count);
|
||||
}
|
||||
});
|
||||
}, [alive, crypto, userId, devices]);
|
||||
|
||||
return unverifiedCount;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue