This commit is contained in:
rosetta
2026-01-30 05:01:05 +02:00
commit 83f38dc63f
327 changed files with 18725 additions and 0 deletions

View 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>
)
}