'init'
This commit is contained in:
190
app/views/Lockscreen/Lockscreen.tsx
Normal file
190
app/views/Lockscreen/Lockscreen.tsx
Normal file
@@ -0,0 +1,190 @@
|
||||
import { Anchor, AspectRatio, Avatar, Box, Flex, PasswordInput, Skeleton, Text, Transition} from "@mantine/core";
|
||||
import classes from './Lockscreen.module.css'
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useWindow from "@/app/hooks/useWindow";
|
||||
import { decodeWithPassword, generateHashFromPrivateKey } from "@/app/crypto/crypto";
|
||||
import { useAccountProvider } from "@/app/providers/AccountProvider/useAccountProvider";
|
||||
import { Account, AccountBase } from "@/app/providers/AccountProvider/AccountProvider";
|
||||
import { useUserCache } from "@/app/providers/InformationProvider/useUserCache";
|
||||
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
||||
import { IconArrowsExchange, IconFingerprint } from "@tabler/icons-react";
|
||||
import { SIZE_LOGIN_WIDTH_PX } from "@/app/constants";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { useAvatars } from "@/app/providers/AvatarProvider/useAvatars";
|
||||
import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton";
|
||||
import { DiceDropdown } from "@/app/components/DiceDropdown/DiceDropdown";
|
||||
import { dotCenterIfNeeded } from "@/app/utils/utils";
|
||||
|
||||
export function Lockscreen() {
|
||||
const [password, setPassword] = useState("");
|
||||
const navigate = useNavigate();
|
||||
const { setSize, setResizeble } = useWindow();
|
||||
const { allAccounts, selectAccountToLoginDice, loginDiceAccount, loginAccount } = useAccountProvider();
|
||||
const userInfo = useUserCache(loginDiceAccount.publicKey);
|
||||
const [error, setError] = useState(false);
|
||||
const colors = useRosettaColors();
|
||||
const avatars = useAvatars(loginDiceAccount.publicKey);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setSize(385, 555);
|
||||
setResizeble(false);
|
||||
setTimeout(() => setMounted(true), 100);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (loginDiceAccount.publicKey == "" && allAccounts.length <= 0) {
|
||||
navigate("/");
|
||||
return;
|
||||
}
|
||||
}, [loginDiceAccount])
|
||||
|
||||
const onUnlockPressed = async () => {
|
||||
try {
|
||||
const decryptedHex = await decodeWithPassword(password, loginDiceAccount.privateKey);
|
||||
const privateKeyHash = await generateHashFromPrivateKey(decryptedHex);
|
||||
|
||||
const account: Account = {
|
||||
privateKey: loginDiceAccount.privateKey,
|
||||
publicKey: loginDiceAccount.publicKey,
|
||||
privateHash: privateKeyHash,
|
||||
privatePlain: decryptedHex,
|
||||
seedPhraseEncrypted: loginDiceAccount.seedPhraseEncrypted
|
||||
};
|
||||
|
||||
loginAccount(account);
|
||||
|
||||
navigate("/main");
|
||||
} catch (e) {
|
||||
setError(true);
|
||||
}
|
||||
}
|
||||
|
||||
const createAccount = () => {
|
||||
modals.openConfirmModal({
|
||||
title: 'Create account',
|
||||
centered: true,
|
||||
children: (
|
||||
<Text size="sm">
|
||||
You may be create new account or import existing
|
||||
</Text>
|
||||
),
|
||||
withCloseButton: false,
|
||||
labels: { confirm: 'Create new', cancel: "Import" },
|
||||
cancelProps: {
|
||||
autoFocus: false,
|
||||
style: {
|
||||
outline: 'none'
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
navigate("/exists-seed");
|
||||
},
|
||||
onConfirm: () => {
|
||||
navigate("/create-seed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const selectAccount = (account: AccountBase) => {
|
||||
selectAccountToLoginDice(account);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
onUnlockPressed();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [onUnlockPressed]);
|
||||
|
||||
return (
|
||||
<Flex style={{
|
||||
userSelect: 'none'
|
||||
}} h={500} justify={'space-between'} direction={'column'} align={'center'}>
|
||||
<div className={classes.inner}>
|
||||
<div className={classes.content}>
|
||||
<Flex mt={'md'} align={'center'} direction={'column'} justify={'center'}>
|
||||
{userInfo && (
|
||||
<Box mt={'sm'}>
|
||||
<Flex align={'center'} gap={'sm'} direction={'column'}>
|
||||
<AspectRatio ratio={2/2} maw={80} mx="auto" pos="relative">
|
||||
<Avatar radius={'md'} src={avatars.length > 0 ? avatars[0].avatar : undefined} size={80} color={'initials'} name={userInfo.title}></Avatar>
|
||||
</AspectRatio>
|
||||
<Flex gap={8} justify={'center'} align={'center'}>
|
||||
<Text fz={20} h={25} fw={'bold'}>{dotCenterIfNeeded(userInfo.title, 20, 5)}</Text>
|
||||
<DiceDropdown selectedPublicKey={loginDiceAccount.publicKey} onClick={selectAccount}>
|
||||
<IconArrowsExchange style={{
|
||||
position: 'relative',
|
||||
top: 4,
|
||||
cursor: 'pointer'
|
||||
}} color={colors.brandColor} size={18} />
|
||||
</DiceDropdown>
|
||||
</Flex>
|
||||
<Text c={'dimmed'} mt={'xs'} ta={'center'} w={SIZE_LOGIN_WIDTH_PX} size={'xs'}>For unlock account enter password</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
{!userInfo && (
|
||||
<Box>
|
||||
<Flex align={'center'} gap={'sm'} direction={'column'} justify={'center'}>
|
||||
<Skeleton w={80} h={80}></Skeleton>
|
||||
<Skeleton h={25} w={150}></Skeleton>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
<Transition mounted={mounted} transition="slide-up" duration={400} timingFunction="ease">
|
||||
{(styles) => (
|
||||
<Flex style={styles} mt={40} direction={'column'} align={'center'} justify={'center'} gap={'lg'}>
|
||||
<PasswordInput
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => { setPassword(e.target.value); setError(false) }}
|
||||
size="md"
|
||||
w={SIZE_LOGIN_WIDTH_PX}
|
||||
error={error && "Invalid password"}
|
||||
styles={{
|
||||
input: {
|
||||
border: '0px solid ' + colors.borderColor,
|
||||
backgroundColor: colors.mainColor
|
||||
},
|
||||
error: {
|
||||
color: colors.error
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Flex w={SIZE_LOGIN_WIDTH_PX} align={'center'} direction={'column'} justify={'space-between'}>
|
||||
<AnimatedButton fullWidth leftSection={
|
||||
<IconFingerprint size={16} />
|
||||
} animated={['#2DA5FF', '#87DBFF']} size={'md'} onClick={onUnlockPressed}>Enter</AnimatedButton>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<Transition mounted={mounted} transition="slide-up" duration={500} timingFunction="ease">
|
||||
{(styles) => (
|
||||
<Flex style={styles}>
|
||||
<Text c={'dimmed'} ta={'center'} w={SIZE_LOGIN_WIDTH_PX} size={'xs'}>
|
||||
You can also <Anchor style={{
|
||||
textDecoration: 'none'
|
||||
}} fw={500} onClick={() => navigate('/exists-seed')}>recover your password</Anchor> or create a <Anchor style={{
|
||||
textDecoration: 'none'
|
||||
}} fw={500} onClick={createAccount}>new account.</Anchor>
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Transition>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user