Merge pull request #35 from nimbus-gui/rd.fix-connect-screens-flow

Fix connect screens flow
This commit is contained in:
Radoslav Dimchev 2024-01-06 22:39:23 +02:00 committed by GitHub
commit 836521aee4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 536 additions and 544 deletions

View File

@ -1,8 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="20/connection">
<g id="body">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99978 1.8999C8.21669 1.8999 6.48343 2.48826 5.06881 3.57374C3.6542 4.65921 2.63728 6.18114 2.17578 7.90347L3.33489 8.21405C3.72802 6.74688 4.59428 5.45043 5.79933 4.52576C7.00437 3.6011 8.48086 3.0999 9.99978 3.0999C11.5187 3.0999 12.9952 3.6011 14.2002 4.52577C15.4053 5.45043 16.2715 6.74688 16.6647 8.21405L17.8238 7.90347C17.3623 6.18114 16.3454 4.65922 14.9307 3.57374C13.5161 2.48827 11.7829 1.8999 9.99978 1.8999ZM9.99988 4.9C8.87719 4.9 7.78588 5.27045 6.8952 5.9539C6.00451 6.63734 5.36423 7.59559 5.07366 8.68002L6.23277 8.9906C6.45497 8.16133 6.9446 7.42856 7.62571 6.90592C8.30682 6.38329 9.14136 6.1 9.99988 6.1C10.8584 6.1 11.6929 6.38329 12.374 6.90592C13.0552 7.42856 13.5448 8.16134 13.767 8.99061L14.9261 8.68002C14.6355 7.59559 13.9952 6.63735 13.1046 5.9539C12.2139 5.27045 11.1226 4.9 9.99988 4.9ZM9.99988 10.1C8.95054 10.1 8.09988 10.9507 8.09988 12C8.09988 13.0493 8.95054 13.9 9.99988 13.9C11.0492 13.9 11.8999 13.0493 11.8999 12C11.8999 10.9507 11.0492 10.1 9.99988 10.1ZM6.89988 12C6.89988 10.2879 8.2878 8.9 9.99988 8.9C11.712 8.9 13.0999 10.2879 13.0999 12C13.0999 13.5068 12.0248 14.7625 10.5999 15.042V17.5H9.39988V15.042C7.97494 14.7625 6.89988 13.5068 6.89988 12Z" fill="#2F80ED"/>
<path d="M5.06881 3.57374L4.76443 3.17706L5.06881 3.57374ZM2.17578 7.90347L1.69282 7.77406L1.56341 8.25702L2.04637 8.38643L2.17578 7.90347ZM3.33489 8.21405L3.20548 8.69701L3.68845 8.82642L3.81786 8.34346L3.33489 8.21405ZM5.79933 4.52576L6.10371 4.92244L5.79933 4.52576ZM9.99978 3.0999V2.5999V3.0999ZM16.6647 8.21405L16.1817 8.34346L16.3111 8.82642L16.7941 8.69702L16.6647 8.21405ZM17.8238 7.90347L17.9532 8.38643L18.4362 8.25702L18.3067 7.77406L17.8238 7.90347ZM14.9307 3.57374L15.2351 3.17707V3.17706L14.9307 3.57374ZM6.8952 5.9539L6.59082 5.55722H6.59081L6.8952 5.9539ZM9.99988 4.9V5.4V4.9ZM5.07366 8.68002L4.59069 8.55061L4.46128 9.03357L4.94425 9.16298L5.07366 8.68002ZM6.23277 8.9906L6.10336 9.47357L6.58632 9.60298L6.71573 9.12001L6.23277 8.9906ZM9.99988 6.1L9.99988 5.6H9.99988V6.1ZM12.374 6.90592L12.6784 6.50925H12.6784L12.374 6.90592ZM13.767 8.99061L13.284 9.12002L13.4134 9.60298L13.8964 9.47357L13.767 8.99061ZM14.9261 8.68002L15.0555 9.16299L15.5385 9.03358L15.4091 8.55062L14.9261 8.68002ZM13.1046 5.9539L13.4089 5.55722H13.4089L13.1046 5.9539ZM10.5999 15.042L10.5037 14.5513L10.0999 14.6305V15.042H10.5999ZM10.5999 17.5V18H11.0999V17.5H10.5999ZM9.39988 17.5H8.89988V18H9.39988V17.5ZM9.39988 15.042H9.89988V14.6305L9.4961 14.5513L9.39988 15.042ZM5.37319 3.97042C6.70049 2.95195 8.32676 2.3999 9.99978 2.3999V1.3999C8.10663 1.3999 6.26637 2.02458 4.76443 3.17706L5.37319 3.97042ZM2.65874 8.03288C3.09175 6.41686 4.0459 4.98889 5.37319 3.97042L4.76443 3.17706C3.26249 4.32954 2.1828 5.94541 1.69282 7.77406L2.65874 8.03288ZM3.4643 7.73109L2.30519 7.4205L2.04637 8.38643L3.20548 8.69701L3.4643 7.73109ZM5.49495 4.12909C4.20258 5.12075 3.27354 6.51115 2.85193 8.08464L3.81786 8.34346C4.18249 6.98261 4.98598 5.7801 6.10371 4.92244L5.49495 4.12909ZM9.99978 2.5999C8.37079 2.5999 6.78731 3.13742 5.49495 4.12909L6.10371 4.92244C7.22143 4.06478 8.59092 3.5999 9.99978 3.5999V2.5999ZM14.5046 4.12909C13.2122 3.13742 11.6288 2.5999 9.99978 2.5999V3.5999C11.4086 3.5999 12.7781 4.06478 13.8959 4.92244L14.5046 4.12909ZM17.1476 8.08464C16.726 6.51116 15.797 5.12076 14.5046 4.12909L13.8959 4.92244C15.0136 5.7801 15.8171 6.98261 16.1817 8.34346L17.1476 8.08464ZM17.6944 7.42051L16.5353 7.73109L16.7941 8.69702L17.9532 8.38643L17.6944 7.42051ZM14.6264 3.97042C15.9537 4.98889 16.9078 6.41687 17.3408 8.03288L18.3067 7.77406C17.8168 5.94541 16.7371 4.32954 15.2351 3.17707L14.6264 3.97042ZM9.99978 2.3999C11.6728 2.3999 13.2991 2.95195 14.6264 3.97042L15.2351 3.17706C13.7332 2.02459 11.8929 1.3999 9.99978 1.3999V2.3999ZM7.19958 6.35057C8.00294 5.73413 8.98726 5.4 9.99988 5.4V4.4C8.76713 4.4 7.56882 4.80677 6.59082 5.55722L7.19958 6.35057ZM5.55662 8.80943C5.8187 7.83132 6.39621 6.96702 7.19958 6.35057L6.59081 5.55722C5.61281 6.30767 4.90975 7.35987 4.59069 8.55061L5.55662 8.80943ZM6.36218 8.50764L5.20307 8.19706L4.94425 9.16298L6.10336 9.47357L6.36218 8.50764ZM7.32133 6.50924C6.55289 7.09889 6.00049 7.92561 5.7498 8.86119L6.71573 9.12001C6.90945 8.39706 7.3363 7.75823 7.93009 7.3026L7.32133 6.50924ZM9.99988 5.6C9.03129 5.6 8.08976 5.9196 7.32133 6.50924L7.93009 7.3026C8.52388 6.84697 9.25142 6.6 9.99988 6.6V5.6ZM12.6784 6.50925C11.91 5.91961 10.9685 5.6 9.99988 5.6L9.99988 6.6C10.7483 6.6 11.4759 6.84697 12.0697 7.3026L12.6784 6.50925ZM14.25 8.8612C13.9993 7.92561 13.4469 7.09889 12.6784 6.50925L12.0697 7.3026C12.6635 7.75823 13.0903 8.39706 13.284 9.12002L14.25 8.8612ZM14.7967 8.19706L13.6376 8.50764L13.8964 9.47357L15.0555 9.16299L14.7967 8.19706ZM12.8002 6.35057C13.6035 6.96702 14.1811 7.83132 14.4431 8.80943L15.4091 8.55062C15.09 7.35987 14.3869 6.30767 13.4089 5.55722L12.8002 6.35057ZM9.99988 5.4C11.0125 5.4 11.9968 5.73413 12.8002 6.35057L13.4089 5.55722C12.4309 4.80677 11.2326 4.4 9.99988 4.4V5.4ZM8.59988 12C8.59988 11.2268 9.22668 10.6 9.99988 10.6V9.6C8.67439 9.6 7.59988 10.6745 7.59988 12H8.59988ZM9.99988 13.4C9.22668 13.4 8.59988 12.7732 8.59988 12H7.59988C7.59988 13.3255 8.67439 14.4 9.99988 14.4V13.4ZM11.3999 12C11.3999 12.7732 10.7731 13.4 9.99988 13.4V14.4C11.3254 14.4 12.3999 13.3255 12.3999 12H11.3999ZM9.99988 10.6C10.7731 10.6 11.3999 11.2268 11.3999 12H12.3999C12.3999 10.6745 11.3254 9.6 9.99988 9.6V10.6ZM9.99988 8.4C8.01165 8.4 6.39988 10.0118 6.39988 12H7.39988C7.39988 10.5641 8.56394 9.4 9.99988 9.4V8.4ZM13.5999 12C13.5999 10.0118 11.9881 8.4 9.99988 8.4V9.4C11.4358 9.4 12.5999 10.5641 12.5999 12H13.5999ZM10.6961 15.5326C12.3511 15.2081 13.5999 13.7504 13.5999 12H12.5999C12.5999 13.2632 11.6985 14.317 10.5037 14.5513L10.6961 15.5326ZM10.0999 15.042V17.5H11.0999V15.042H10.0999ZM10.5999 17H9.39988V18H10.5999V17ZM9.89988 17.5V15.042H8.89988V17.5H9.89988ZM6.39988 12C6.39988 13.7504 7.64864 15.2081 9.30366 15.5326L9.4961 14.5513C8.30124 14.317 7.39988 13.2632 7.39988 12H6.39988Z" fill="#2A4CF4"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -9,15 +9,13 @@ import { useSelector } from 'react-redux'
import config from '../tamagui.config'
import LandingPage from './pages/LandingPage/LandingPage'
import DeviceHealthCheck from './pages/DeviceHealthCheck/DeviceHealthCheck'
import ConnectDevicePage from './pages/ConnectDevicePage/ConnectDevicePage'
import { RootState } from './redux/store'
import DeviceSyncStatus from './pages/DeviceSyncStatus/DeviceSyncStatus'
import PairDevice from './pages/PairDevice/PairDevice'
import PinnedNotification from './components/General/PinnedNottification'
import CreateLocalNodePage from './pages/CreateLocalNodePage/CreateLocalNodePage'
import CreateLocalNode from './pages/CreateLocalNode/CreateLocalNode'
import ValidatorOnboarding from './pages/ValidatorOnboarding/ValidatorOnboarding'
import Dashboard from './pages/Dashboard/Dashboard'
import ConnectExistingInstance from './pages/ConnectExistingInstance/ConnectExistingInstance'
import ValidatorManagement from './pages/ValidatorManagement/ValidatorManagement'
import { ethereumRopsten, wcV2InitOptions, apiKey } from './constants'
import './App.css'
@ -47,10 +45,6 @@ const router = createBrowserRouter([
path: '/device-health-check',
element: <DeviceHealthCheck />,
},
{
path: '/connect-device',
element: <ConnectDevicePage />,
},
{
path: '/device-sync-status',
element: <DeviceSyncStatus />,
@ -59,11 +53,7 @@ const router = createBrowserRouter([
path: '/pair-device',
element: <PairDevice />,
},
{
path: '/pair-existing-instance',
element: <ConnectExistingInstance />,
},
{ path: '/create-local-node', element: <CreateLocalNodePage /> },
{ path: '/create-local-node', element: <CreateLocalNode /> },
{ path: '/validator-onboarding', element: <ValidatorOnboarding /> },
{ path: '/dashboard', element: <Dashboard /> },
{ path: '/validator-management', element: <ValidatorManagement /> },

View File

@ -1,6 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react'
import Header from './Header'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'General/Header',
@ -8,6 +9,7 @@ const meta = {
parameters: {
layout: 'centered',
},
decorators: [withRouter],
tags: ['autodocs'],
} satisfies Meta<typeof Header>
@ -16,18 +18,12 @@ type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
selectedTag: 'pair',
selectedTag: 'Pair',
},
}
export const CreateTag: Story = {
args: {
selectedTag: 'create',
},
}
export const ConnectTag: Story = {
args: {
selectedTag: 'connect',
selectedTag: 'Create',
},
}

View File

@ -1,8 +1,8 @@
import NimbusLogo from '../Logos/NimbusLogo'
import TagContainer from './TagContainer'
import TagContainer, { SelectedTag } from './TagContainer'
type HeaderProps = {
selectedTag: 'pair' | 'create' | 'connect'
selectedTag: SelectedTag
}
const Header = ({ selectedTag }: HeaderProps) => {

View File

@ -2,5 +2,4 @@
background-color: #fff;
border-radius: 12px;
margin-top: 8px;
}

View File

@ -1,5 +1,6 @@
import { Input as StatusInput, Text } from '@status-im/components'
import { Label } from 'tamagui'
import './LabelInputField.css'
type LabelInputProps = {

View File

@ -1,3 +0,0 @@
/* .tag-container div:nth-child(1) {
background:transparent;
} */

View File

@ -1,21 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react'
import ConnectDevicePage from './ConnectDevicePage'
import { withRouter } from 'storybook-addon-react-router-v6'
import TagContainer from './TagContainer'
const meta = {
title: 'Connect-Device/ConnectDevicePage',
component: ConnectDevicePage,
title: 'General/TagContainer',
component: TagContainer,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof ConnectDevicePage>
tags: ['autodocs'],
} satisfies Meta<typeof TagContainer>
export default meta
type Story = StoryObj<typeof meta>
export const Page: Story = {
args: {},
export const Pair: Story = {
args: {
selectedTag: 'Pair',
},
}
export const Create: Story = {
args: {
selectedTag: 'Create',
},
}

View File

@ -1,53 +1,46 @@
import { Tag } from '@status-im/components'
import { XStack } from 'tamagui'
import './TagContainer.css'
import { ConnectionIcon, AddSmallIcon, SwapIcon } from '@status-im/icons'
import { AddSmallIcon, SwapIcon } from '@status-im/icons'
import { useNavigate } from 'react-router'
export type SelectedTag = 'Pair' | 'Create'
type TagContainerProps = {
selectedTag: 'pair' | 'create' | 'connect'
selectedTag: SelectedTag
}
const TAGS = [
{
label: 'Pair',
icon: SwapIcon,
path: '/pair-device',
},
{
label: 'Create',
icon: AddSmallIcon,
path: '/create-local-node',
},
]
const TagContainer = ({ selectedTag }: TagContainerProps) => {
const navigate = useNavigate()
const onPressConnect = () => {
navigate('/connect-device')
}
const onPressPair = () => {
navigate('/pair-device')
}
const onPressCreate = () => {
navigate('/create-local-node')
const onPressTag = (path: string) => {
navigate(path)
}
return (
<XStack space={'$2'} alignItems="center" className="tag-container">
{selectedTag === 'connect' ? (
{TAGS.map(tag => (
<Tag
selected={selectedTag === 'connect'}
icon={ConnectionIcon}
label="Connect"
key={tag.label}
selected={selectedTag === tag.label}
icon={tag.icon}
label={tag.label}
size={32}
onPress={onPressConnect}
onPress={() => onPressTag(tag.path)}
/>
) : null}
<Tag
selected={selectedTag === 'pair'}
icon={SwapIcon}
label="Pair"
size={32}
onPress={onPressPair}
/>
<Tag
selected={selectedTag === 'create'}
icon={AddSmallIcon}
label="Create"
size={32}
onPress={onPressCreate}
/>
))}
</XStack>
)
}

View File

@ -113,3 +113,12 @@ export const VALIDATORS_DATA = [
status: 'Active',
},
]
// Pair Device
export const VC = 'VC'
export const VALIDATOR_CLIENT = 'Validator Client'
export const BEACON = 'Beacon'
export const NODE = 'Node'
export const VC_PORT = '9000'
export const BEACON_PORT = '5052'
export const DEFAULT_ADDRESS = 'http://124.0.0.1'

View File

@ -1,130 +0,0 @@
import { NodeIcon } from '@status-im/icons'
import { useEffect, useState } from 'react'
import { Button as StatusButton, Text, Checkbox } from '@status-im/components'
import { Article, Label, Separator, Stack, XStack, YStack } from 'tamagui'
import BreadcrumbBar from '../../components/General/BreadcrumbBar/BreadcrumbBar'
import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow'
import Titles from '../../components/General/Titles'
import LabelInputField from '../../components/General/LabelInputField'
import Header from '../../components/General/Header'
import CreateAvatar from '../../components/General/CreateAvatar/CreateAvatar'
const ConnectDevicePage = () => {
const [autoConnectChecked, setAutoConnectChecked] = useState(false)
const [portChecked, setPortChecked] = useState(false)
const [windowWidth, setWindowWidth] = useState(window.innerWidth)
useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth)
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
const breakpoint = 268
const responsiveXStackStyle = {
space: '$4',
alignItems: 'center',
flexDirection: windowWidth <= breakpoint ? 'column' : 'row',
width: '55%',
}
const checkboxStackStyle = {
marginTop: '20px',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
}
const responsiveInputStyle = {
marginBottom: windowWidth <= breakpoint ? '0.5rem' : '0',
width: '100%',
}
return (
<PageWrapperShadow
breadcrumbBar={<BreadcrumbBar breadcrumbList={['Nodes', 'Nimbus', 'Connect Device']} />}
rightImageSrc="./background-images/day-night-bg.png"
rightImageLogo={true}
>
<YStack space={'$3'}>
<Header selectedTag="connect" />
<Article className="content">
<Titles
title="Connect Device"
subtitle="Configure your device to connect to the Nimbus Node Manager"
/>
<YStack my={16} width={'50%'}>
<XStack style={responsiveXStackStyle} space={'$3'}>
<Stack style={responsiveInputStyle}>
<LabelInputField
labelText="Beacon Address"
placeholderText="something"
width="100%"
/>
</Stack>
<Stack style={responsiveInputStyle}>
<LabelInputField labelText="Beacon Node Port" placeholderText="5052" width="100%" />
</Stack>
<Stack style={responsiveInputStyle}>
<LabelInputField
labelText="Client Validator Port"
placeholderText="5052"
width="100%"
/>
</Stack>
<YStack width={20} style={checkboxStackStyle}>
<Checkbox
id="port-checkbox"
variant="outline"
selected={portChecked}
onCheckedChange={v => setPortChecked(v)}
/>
</YStack>
</XStack>
<XStack alignItems="center" width="100%">
<LabelInputField
labelText="API Token"
placeholderText="****_*****_*****"
width="180%"
/>
</XStack>
</YStack>
<YStack my={16}>
<CreateAvatar></CreateAvatar>
</YStack>
<Separator alignSelf="stretch" borderColor={'#F0F2F5'} />
<YStack my={16}>
<YStack>
<Text size={19} weight="semibold">
Settings
</Text>
</YStack>
<XStack my={8} space={'$2'}>
<Checkbox
id="auto-connect"
selected={autoConnectChecked}
onCheckedChange={v => setAutoConnectChecked(v)}
variant="outline"
/>
<Label htmlFor="auto-connect">
<Text size={15} weight="regular">
Auto Connect Device
</Text>
</Label>
</XStack>
<Separator alignSelf="stretch" borderColor={'#F0F2F5'} />
</YStack>
<div>
<StatusButton icon={<NodeIcon size={20} />}>Connect Device</StatusButton>
</div>
</Article>
</YStack>
</PageWrapperShadow>
)
}
export default ConnectDevicePage

View File

@ -1,88 +0,0 @@
import { Checkbox, Input, Text } from '@status-im/components'
import { useState } from 'react'
import { Stack, Switch, XStack, YStack } from 'tamagui'
const BeaconAddress = () => {
const [isBeaconSwitchOn, setIsBeaconSwitchOn] = useState(false)
const [inputAdress, setInputAdress] = useState('')
const [vcPort, setVcPort] = useState('')
const [isClientAddressChecked, setIsClientAddressChecked] = useState(false)
return (
<YStack>
<XStack justifyContent={'space-between'}>
<YStack space={'$2'}>
<YStack>
<Text size={13} color={'#647084'} weight={'semibold'}>
{' '}
Protocol{' '}
</Text>
<Text size={11} color={'#647084'} weight={'regular'}>
{' '}
(HTTP/HTTPS)
</Text>
</YStack>
<Switch
size="$1"
style={isBeaconSwitchOn ? { backgroundColor: '#2A4AF5' } : { backgroundColor: 'grey' }}
checked={isBeaconSwitchOn}
onCheckedChange={() => setIsBeaconSwitchOn(prev => !prev)}
>
<Switch.Thumb
style={{
right: 7,
bottom: 3,
backgroundColor: '#fff',
height: '16px',
width: '16px',
}}
/>
</Switch>
</YStack>
<YStack space={'$2'}>
<Text size={11} color={'#647084'} weight={'regular'}>
Beacon Address
</Text>
<Input
placeholder={''}
value={inputAdress}
onChangeText={e => {
setInputAdress(e)
}}
/>
</YStack>
<YStack space={'$2'}>
<Text size={11} color={'#647084'} weight={'regular'}>
VC Port
</Text>
<Input
placeholder={''}
value={vcPort}
onChangeText={e => {
setVcPort(e)
}}
/>
</YStack>
<Stack
style={{ alignItems: 'center', justifyContent: 'center' }}
height={'100%'}
marginTop={'10px'}
width={'fit-content'}
>
<Checkbox
id="checkforaddress"
variant="outline"
selected={isClientAddressChecked}
onCheckedChange={() => setIsClientAddressChecked(prev => !prev)}
size={20}
/>
</Stack>
</XStack>
<XStack></XStack>
</YStack>
)
}
export default BeaconAddress

View File

@ -1,87 +0,0 @@
import { Checkbox, Input, Text } from '@status-im/components'
import { useState } from 'react'
import { Stack, Switch, XStack, YStack } from 'tamagui'
const ClientAddressRow = () => {
const [isBeaconSwitchOn, setIsBeaconSwitchOn] = useState(false)
const [inputAdress, setInputAdress] = useState('')
const [vcPort, setVcPort] = useState('')
const [isClientAddressChecked, setIsClientAddressChecked] = useState(false)
return (
<YStack>
<XStack justifyContent={'space-between'}>
<YStack space={'$2'}>
<YStack>
<Text size={13} color={'#647084'} weight={'semibold'}>
{' '}
Protocol{' '}
</Text>
<Text size={11} color={'#647084'} weight={'regular'}>
{' '}
(HTTP/HTTPS)
</Text>
</YStack>
<Switch
size="$1"
style={isBeaconSwitchOn ? { backgroundColor: '#2A4AF5' } : { backgroundColor: 'grey' }}
checked={isBeaconSwitchOn}
onCheckedChange={() => setIsBeaconSwitchOn(prev => !prev)}
>
<Switch.Thumb
style={{
right: 7,
bottom: 3,
backgroundColor: '#fff',
height: '16px',
width: '16px',
}}
/>
</Switch>
</YStack>
<YStack space={'$2'}>
<Text size={11} color={'#647084'} weight={'regular'}>
Validator Client Address
</Text>
<Input
placeholder={''}
value={inputAdress}
onChangeText={e => {
setInputAdress(e)
}}
/>
</YStack>
<YStack space={'$2'}>
<Text size={11} color={'#647084'} weight={'regular'}>
VC Port
</Text>
<Input
placeholder={''}
value={vcPort}
onChangeText={e => {
setVcPort(e)
}}
/>
</YStack>
<Stack
style={{ alignItems: 'center', justifyContent: 'center' }}
height={'100%'}
marginTop={'10px'}
width={'fit-content'}
>
<Checkbox
id="checkforaddress"
variant="outline"
selected={isClientAddressChecked}
onCheckedChange={() => setIsClientAddressChecked(prev => !prev)}
size={20}
/>
</Stack>
</XStack>
<XStack></XStack>
</YStack>
)
}
export default ClientAddressRow

View File

@ -1,21 +0,0 @@
import type { Meta, StoryObj } from '@storybook/react'
import ConnectExistingInstance from './ConnectExistingInstance'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'Connect-Device/ConnectExistingInstance',
component: ConnectExistingInstance,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof ConnectExistingInstance>
export default meta
type Story = StoryObj<typeof meta>
export const Page: Story = {
args: {},
}

View File

@ -1,83 +0,0 @@
import { Separator, XStack, YStack } from 'tamagui'
import { useState } from 'react'
import { Button, Input, Text } from '@status-im/components'
import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow'
import Titles from '../../components/General/Titles'
import { NodeIcon, SettingsIcon, CompleteIdIcon, ClearIcon } from '@status-im/icons'
import Header from '../../components/General/Header'
import ClientAddressRow from './ClientAddressRow'
import BeaconAddress from './BeaconAddress'
const ConnectExistingInstance = () => {
const [encryptedPassword, setEncryptedPassword] = useState('')
const changeEncryptedPasswordHandler = (value: string) => {
setEncryptedPassword(value)
}
return (
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
<YStack
space={'$3'}
style={{
maxWidth: '100%',
}}
>
<Header selectedTag="pair" />
<Titles
title="Connect to existing Nimbus Instance"
subtitle="Pair your existing device to the Nimbus Node Manager "
/>
<XStack style={{ justifyContent: 'space-between' }}>
<Text size={19} weight={'semibold'} color="#09101C">
Connect via IP
</Text>
<Button variant="grey" size={24} icon={<SettingsIcon size={20} />}>
Advanced
</Button>
</XStack>
<ClientAddressRow />
<BeaconAddress />
<Separator borderColor={'#e3e3e3'} />
<YStack space={'$2'}>
<Text size={11} color={'#647084'}>
API Token
</Text>
<Input
placeholder={'*****_*******_******'}
icon={
<ClearIcon
size={16}
color="#A1ABBD"
onClick={() => setEncryptedPassword('')}
style={{ cursor: 'pointer' }}
/>
}
value={encryptedPassword}
onChangeText={changeEncryptedPasswordHandler}
/>
</YStack>
<Separator borderColor={'#e3e3e3'} />
<Text size={19} weight={'semibold'} color="#09101C">
Advanced Settings
</Text>
<XStack space={'$4'}>
<Button icon={<CompleteIdIcon size={20} color="#2A4AF5" />} variant="outline">
Pair with ID
</Button>
</XStack>
<Separator borderColor={'#e3e3e3'} />
<XStack>
<Button icon={<NodeIcon size={20} />} variant="blue">
Continue
</Button>
</XStack>
</YStack>
</PageWrapperShadow>
)
}
export default ConnectExistingInstance

View File

@ -1,17 +1,17 @@
import type { Meta, StoryObj } from '@storybook/react'
import BeaconAddress from './BeaconAddress'
import CreateLocalNode from './CreateLocalNode'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'Connect-Device/BeaconAddress',
component: BeaconAddress,
title: 'Pages/CreateLocalNode',
component: CreateLocalNode,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof BeaconAddress>
} satisfies Meta<typeof CreateLocalNode>
export default meta
type Story = StoryObj<typeof meta>

View File

@ -2,26 +2,25 @@ import { useState } from 'react'
import { Button as StatusButton, Text, Checkbox } from '@status-im/components'
import { NodeIcon } from '@status-im/icons'
import { Label, Separator, XStack, YStack } from 'tamagui'
import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow'
import Header from '../../components/General/Header'
import Titles from '../../components/General/Titles'
import CreateAvatar from '../../components/General/CreateAvatar/CreateAvatar'
const CreateLocalNodePage = () => {
const CreateLocalNode = () => {
const [autoConnectChecked, setAutoConnectChecked] = useState(false)
return (
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
<YStack space={'$3'}>
<Header selectedTag="create" />
<Header selectedTag="Create" />
<article className="content">
<Titles
title="Create Local Node"
subtitle="Configure your device to start Staking on Nimbus"
/>
<CreateAvatar />
<YStack my={16}>
<Text size={19} weight="semibold">
Settings
@ -48,4 +47,4 @@ const CreateLocalNodePage = () => {
)
}
export default CreateLocalNodePage
export default CreateLocalNode

View File

@ -1,21 +0,0 @@
import type { Meta, StoryObj } from '@storybook/react'
import CreateLocalNodePage from './CreateLocalNodePage'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'Connect-Device/CreateLocalNodePage',
component: CreateLocalNodePage,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof CreateLocalNodePage>
export default meta
type Story = StoryObj<typeof meta>
export const Page: Story = {
args: {},
}

View File

@ -1,21 +1,21 @@
import type { Meta, StoryObj } from '@storybook/react'
import ClientAddressRow from './ClientAddressRow'
import { withRouter } from 'storybook-addon-react-router-v6'
import ConnectViaIP from './ConnectViaIP'
const meta = {
title: 'Connect-Device/ClientAddressRow',
component: ClientAddressRow,
title: 'Pair Device/ConnectViaIP',
component: ConnectViaIP,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof ClientAddressRow>
} satisfies Meta<typeof ConnectViaIP>
export default meta
type Story = StoryObj<typeof meta>
export const Page: Story = {
export const Default: Story = {
args: {},
}

View File

@ -0,0 +1,96 @@
import { Separator, XStack, YStack } from 'tamagui'
import { useState } from 'react'
import { Button, Input, Text } from '@status-im/components'
import { SettingsIcon, ClearIcon } from '@status-im/icons'
import { useSelector } from 'react-redux'
import InputsRow from './InputsRow'
import { RootState } from '../../../redux/store'
import { BEACON, NODE, VALIDATOR_CLIENT, VC } from '../../../constants'
const ConnectViaIP = () => {
const [apiToken, setApiToken] = useState('')
const [isAdvanced, setIsAdvanced] = useState(false)
const {
beaconPort,
vcPort,
nodeAddress,
beaconAddress,
vcAddress,
isBeaconSwitchOn,
isVcSwitchOn,
isBeaconChecked,
isVcChecked,
} = useSelector((state: RootState) => state.pairDevice)
const changeApiToken = (value: string) => {
setApiToken(value)
}
const onAdvancedClickHandler = () => {
setIsAdvanced(state => !state)
}
return (
<YStack space={'$3'} maxWidth={'100%'}>
<XStack style={{ justifyContent: 'space-between' }}>
<Text size={19} weight={'semibold'} color="#09101C">
Connect via IP
</Text>
<Button
variant={isAdvanced ? 'darkGrey' : 'grey'}
size={32}
icon={<SettingsIcon size={20} />}
onPress={onAdvancedClickHandler}
>
Advanced
</Button>
</XStack>
{isAdvanced ? (
<YStack space={'$3'}>
<InputsRow
addressType={VALIDATOR_CLIENT}
portType={VC}
address={vcAddress}
port={vcPort}
isAdvanced={isAdvanced}
isSwitchOn={isVcSwitchOn}
isChecked={isVcChecked}
/>
<InputsRow
addressType={BEACON}
portType={BEACON}
address={beaconAddress}
port={beaconPort}
isAdvanced={isAdvanced}
isSwitchOn={isBeaconSwitchOn}
isChecked={isBeaconChecked}
/>
</YStack>
) : (
<InputsRow addressType={NODE} address={nodeAddress} port={''} portType={''} />
)}
<Separator borderColor={'#e3e3e3'} />
<YStack space={'$2'}>
<Text size={13} color={'#647084'} weight={'semibold'}>
API Token
</Text>
<Input
placeholder={'*****_*******_******'}
icon={
<ClearIcon
size={16}
color="#A1ABBD"
onClick={() => changeApiToken('')}
style={{ cursor: 'pointer' }}
/>
}
value={apiToken}
onChangeText={changeApiToken}
/>
</YStack>
</YStack>
)
}
export default ConnectViaIP

View File

@ -0,0 +1,59 @@
import type { Meta, StoryObj } from '@storybook/react'
import { withRouter } from 'storybook-addon-react-router-v6'
import InputsRow from './InputsRow'
import {
BEACON,
BEACON_PORT,
DEFAULT_ADDRESS,
NODE,
VALIDATOR_CLIENT,
VC,
VC_PORT,
} from '../../../constants'
const meta = {
title: 'Pair Device/InputsRow',
component: InputsRow,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof InputsRow>
export default meta
type Story = StoryObj<typeof meta>
export const Node: Story = {
args: {
addressType: NODE,
address: DEFAULT_ADDRESS,
port: '',
portType: '',
},
}
export const ValidatorClient: Story = {
args: {
addressType: VALIDATOR_CLIENT,
portType: VC,
address: DEFAULT_ADDRESS,
port: VC_PORT,
isAdvanced: true,
isSwitchOn: true,
isChecked: true,
},
}
export const Beacon: Story = {
args: {
addressType: BEACON,
portType: BEACON,
address: DEFAULT_ADDRESS,
port: BEACON_PORT,
isAdvanced: true,
isSwitchOn: true,
isChecked: true,
},
}

View File

@ -0,0 +1,106 @@
import { Checkbox, Input, Text } from '@status-im/components'
import { useDispatch, useSelector } from 'react-redux'
import { Stack, Switch, XStack, YStack } from 'tamagui'
import { RootState } from '../../../redux/store'
import PortInput from './PortInput'
import { BEACON, VC } from '../../../constants'
type InputsRowProps = {
addressType: string
portType: string
isAdvanced?: boolean
address: string
port: string
isSwitchOn?: boolean
isChecked?: boolean
}
const InputsRow = ({
isAdvanced,
addressType,
portType,
address,
port,
isSwitchOn,
isChecked,
}: InputsRowProps) => {
const { beaconPort, vcPort, isNodeChecked, isNodeSwitchOn } = useSelector(
(state: RootState) => state.pairDevice,
)
const dispatch = useDispatch()
const isSwitchOnResult = isAdvanced ? isSwitchOn : isNodeSwitchOn
const switchStyle = isSwitchOnResult
? { backgroundColor: '#2A4AF5' }
: { backgroundColor: 'grey' }
const onSwitchChange = (value: boolean) => {
dispatch({ type: 'pairDevice/setIsSwitchOn', payload: { value, switchType: addressType } })
}
const onCheckboxChange = (value: boolean) => {
dispatch({ type: 'pairDevice/setIsChecked', payload: { value, checkType: addressType } })
}
const onAddressChange = (value: string) => {
dispatch({ type: 'pairDevice/setAddress', payload: { value, addressType } })
}
return (
<XStack space={'$3'}>
<YStack space={'$2'} flexBasis={0} flexGrow={2}>
<YStack>
<Text size={13} color={'#647084'} weight={'semibold'}>
Protocol
</Text>
<Text size={11} color={'#647084'}>
(HTTP/HTTPS)
</Text>
</YStack>
<Switch
size="$1"
style={switchStyle}
checked={isSwitchOnResult}
onCheckedChange={onSwitchChange}
>
<Switch.Thumb
style={{
right: 7.6,
bottom: 2.4,
backgroundColor: '#fff',
height: '16px',
width: '16px',
}}
/>
</Switch>
</YStack>
<YStack space={'$2'} flexBasis={0} flexGrow={isAdvanced ? 5 : 4}>
<Text size={13} color={'#647084'} weight={'semibold'}>
{addressType} Address
</Text>
<Input value={address} onChangeText={onAddressChange} />
</YStack>
{isAdvanced ? (
<PortInput port={port} portType={portType} />
) : (
<XStack space={'$3'} flexGrow={4} flexBasis={0}>
<PortInput port={vcPort} portType={VC} />
<PortInput port={beaconPort} portType={BEACON} />
</XStack>
)}
<div style={{ display: 'flex', alignItems: 'end', height: '100%' }}>
<Stack height={'46%'} flexBasis={0} flexGrow={0.5}>
<Checkbox
id="AddressAndPortInputs"
variant="outline"
selected={isAdvanced ? isChecked : isNodeChecked}
onCheckedChange={onCheckboxChange}
size={20}
/>
</Stack>
</div>
</XStack>
)
}
export default InputsRow

View File

@ -0,0 +1,32 @@
import type { Meta, StoryObj } from '@storybook/react'
import { withRouter } from 'storybook-addon-react-router-v6'
import PortInput from './PortInput'
import { BEACON, BEACON_PORT, VC, VC_PORT } from '../../../constants'
const meta = {
title: 'Pair Device/PortInput',
component: PortInput,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof PortInput>
export default meta
type Story = StoryObj<typeof meta>
export const ValidatorClient: Story = {
args: {
port: VC_PORT,
portType: VC,
},
}
export const Beacon: Story = {
args: {
port: BEACON_PORT,
portType: BEACON,
},
}

View File

@ -0,0 +1,31 @@
import { Input, Text } from '@status-im/components'
import { useDispatch } from 'react-redux'
import { YStack } from 'tamagui'
type PortInputProps = {
portType: string
port: string
}
const PortInput = ({ portType, port }: PortInputProps) => {
const dispatch = useDispatch()
const onPortChange = (value: string) => {
if (isNaN(Number(value))) {
return
}
dispatch({ type: 'pairDevice/setPort', payload: { value, portType } })
}
return (
<YStack space={'$2'} flexBasis={0} flexGrow={3}>
<Text size={13} color={'#647084'} weight={'semibold'}>
{portType} Port
</Text>
<Input value={port} onChangeText={onPortChange} />
</YStack>
)
}
export default PortInput

View File

@ -4,7 +4,7 @@ import { withRouter } from 'storybook-addon-react-router-v6'
import PairDevice from './PairDevice'
const meta = {
title: 'Connect-Device/PairDevice',
title: 'Pages/PairDevice',
component: PairDevice,
parameters: {
layout: 'centered',

View File

@ -1,8 +1,7 @@
import { NodeIcon } from '@status-im/icons'
import { Separator, XStack, YStack } from 'tamagui'
import { NodeIcon, CompleteIdIcon, ConnectionIcon } from '@status-im/icons'
import { Label, Separator, XStack, YStack } from 'tamagui'
import { useState } from 'react'
import { Button, Text } from '@status-im/components'
import { useNavigate } from 'react-router-dom'
import { Button, Checkbox, Text } from '@status-im/components'
import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow'
import SyncStatus from './SyncStatus'
@ -11,11 +10,12 @@ import PairedSuccessfully from './PairedSuccessfully'
import CreateAvatar from '../../components/General/CreateAvatar/CreateAvatar'
import GenerateId from './GenerateId'
import Header from '../../components/General/Header'
import Icon from '../../components/General/Icon'
import ConnectViaIP from './ConnectViaIP/ConnectViaIP'
const PairDevice = () => {
const [isAwaitingPairing, setIsAwaitingPairing] = useState(false)
const navigate = useNavigate()
const [isConnectingViaIp, setIsConnectingViaIp] = useState(false)
const [isAutoConnectChecked, setIsAutoConnectChecked] = useState(false)
const isPaired = false
const isPairing = false
@ -23,27 +23,58 @@ const PairDevice = () => {
setIsAwaitingPairing(result)
}
const connectViaIpHandler = () => {
navigate('/connect-device')
const connectAndPairHandler = () => {
setIsConnectingViaIp(state => !state)
}
const continueHandler = () => {}
return (
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
<YStack space={'$3'}>
<Header selectedTag="pair" />
<Header selectedTag="Pair" />
<Titles
title="Connect to existing Nimbus Instance"
subtitle="Pair your existing device to the Nimbus Node Manager"
/>
{isPaired ? <PairedSuccessfully /> : <GenerateId isAwaitingPairing={isAwaitingPairing} />}
{isPaired === false && (
<SyncStatus
isPairing={isPairing}
isAwaitingPairing={isAwaitingPairing}
changeSetIsAwaitingPairing={changeSetIsAwaitingPairing}
/>
{isConnectingViaIp ? (
<ConnectViaIP />
) : isPaired ? (
<PairedSuccessfully />
) : (
<>
<GenerateId isAwaitingPairing={isAwaitingPairing} />
<SyncStatus
isPairing={isPairing}
isAwaitingPairing={isAwaitingPairing}
changeSetIsAwaitingPairing={changeSetIsAwaitingPairing}
/>
</>
)}
{isPaired === false && (
{isPaired ? (
<>
<YStack space={'$3'}>
<Separator alignSelf="stretch" borderColor={'#F0F2F5'} marginTop={3} />
<Text size={19} weight="semibold">
General Settings
</Text>
<XStack space={'$4'} alignItems={'center'}>
<Checkbox
id="auto-connect"
selected={isAutoConnectChecked}
onCheckedChange={e => setIsAutoConnectChecked(e)}
variant="outline"
/>
<Label htmlFor="auto-connect">
<Text size={15} weight="regular">
Auto Connect Paired Device
</Text>
</Label>
</XStack>
</YStack>
<CreateAvatar />
</>
) : (
<YStack space={'$3'}>
<Separator borderColor={'#e3e3e3'} />
<YStack space={'$1'}>
@ -52,21 +83,26 @@ const PairDevice = () => {
</Text>
<XStack>
<Button
icon={<Icon src="/icons/connection-blue.svg" width={20} />}
icon={
isConnectingViaIp ? <CompleteIdIcon size={20} /> : <ConnectionIcon size={20} />
}
variant="outline"
onPress={connectViaIpHandler}
onPress={connectAndPairHandler}
>
Connect via IP
{isConnectingViaIp ? 'Pair with ID' : 'Connect via IP'}
</Button>
</XStack>
</YStack>
</YStack>
)}
{isPaired && <CreateAvatar />}
<Separator borderColor={'#e3e3e3'} />
<div>
<Button icon={<NodeIcon size={20} />} disabled={!isPaired}>
Continue
<Button
icon={<NodeIcon size={20} />}
disabled={isConnectingViaIp ? false : !isPaired}
onPress={continueHandler}
>
{isConnectingViaIp ? 'Connect Device' : 'Continue'}
</Button>
</div>
</YStack>

View File

@ -0,0 +1,76 @@
import { createSlice } from '@reduxjs/toolkit'
import { BEACON, BEACON_PORT, DEFAULT_ADDRESS, VALIDATOR_CLIENT, VC_PORT } from '../../constants'
type PairDeviceStateType = {
beaconPort: string
vcPort: string
nodeAddress: string
beaconAddress: string
vcAddress: string
isNodeSwitchOn: boolean
isBeaconSwitchOn: boolean
isVcSwitchOn: boolean
isNodeChecked: boolean
isBeaconChecked: boolean
isVcChecked: boolean
}
const initialState: PairDeviceStateType = {
beaconPort: BEACON_PORT,
vcPort: VC_PORT,
nodeAddress: DEFAULT_ADDRESS,
beaconAddress: DEFAULT_ADDRESS,
vcAddress: DEFAULT_ADDRESS,
isNodeSwitchOn: true,
isBeaconSwitchOn: true,
isVcSwitchOn: true,
isNodeChecked: true,
isBeaconChecked: true,
isVcChecked: true,
}
const pairDeviceSlice = createSlice({
name: 'pairDevice',
initialState,
reducers: {
setPort: (state, action) => {
if (action.payload.portType === BEACON) {
state.beaconPort = action.payload.value
} else {
state.vcPort = action.payload.value
}
},
setAddress: (state, action) => {
if (action.payload.addressType === BEACON) {
state.beaconAddress = action.payload.value
} else if (action.payload.addressType === VALIDATOR_CLIENT) {
state.vcAddress = action.payload.value
} else {
state.nodeAddress = action.payload.value
}
},
setIsSwitchOn: (state, action) => {
if (action.payload.switchType === BEACON) {
state.isBeaconSwitchOn = action.payload.value
} else if (action.payload.switchType === VALIDATOR_CLIENT) {
state.isVcSwitchOn = action.payload.value
} else {
state.isNodeSwitchOn = action.payload.value
}
},
setIsChecked: (state, action) => {
if (action.payload.checkType === BEACON) {
state.isBeaconChecked = action.payload.value
} else if (action.payload.checkType === VALIDATOR_CLIENT) {
state.isVcChecked = action.payload.value
} else {
state.isNodeChecked = action.payload.value
}
},
},
})
export const {} = pairDeviceSlice.actions
export default pairDeviceSlice.reducer

View File

@ -11,6 +11,7 @@ import rightSidebarReducer from './RightSidebar/slice'
import validatorOnboardingReducer from './ValidatorOnboarding/slice'
import advisoriesReducer from './ValidatorOnboarding/Advisories/slice'
import validatorSetupReducer from './ValidatorOnboarding/ValidatorSetup/slice'
import pairDeviceReducer from './PairDevice/slice'
const store = configureStore({
reducer: {
@ -25,6 +26,7 @@ const store = configureStore({
validatorOnboarding: validatorOnboardingReducer,
advisories: advisoriesReducer,
validatorSetup: validatorSetupReducer,
pairDevice: pairDeviceReducer,
},
})