Merge pull request #37 from nimbus-gui/rd.connect-via-ip-responsive

Connect via ip responsive
This commit is contained in:
Radoslav Dimchev 2024-01-24 20:44:14 +02:00 committed by GitHub
commit 5078db3a59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 139 additions and 113 deletions

View File

@ -3,25 +3,27 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>Vite + React + TS</title> <title>Nimbus GUI</title>
<link <link
rel="preload" rel="preload"
href="./Inter-font/Inter-Regular.ttf" href="./Inter-font/Inter-Regular.ttf"
as="font" as="font"
type="font/ttf" type="font/ttf"
crossOrigin="" crossorigin=""
/> />
<link <link
rel="preload" rel="preload"
href="./Inter-font/Inter-Bold.ttf" href="./Inter-font/Inter-Bold.ttf"
as="font" as="font"
type="font/ttf" type="font/ttf"
crossOrigin="" crossorigin=""
/> />
</head> </head>
<body> <body>
<script>window.global = window;</script> <script>
window.global = window
</script>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.tsx"></script> <script type="module" src="/src/main.tsx"></script>
</body> </body>

View File

@ -2,16 +2,17 @@ import { Separator, XStack, YStack } from 'tamagui'
import { useState } from 'react' import { useState } from 'react'
import { Button, Input, Text } from '@status-im/components' import { Button, Input, Text } from '@status-im/components'
import { SettingsIcon, ClearIcon } from '@status-im/icons' import { SettingsIcon, ClearIcon } from '@status-im/icons'
import { useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import InputsRow from './InputsRow' import InputsRow from './InputsRow'
import { RootState } from '../../../redux/store' import { RootState } from '../../../redux/store'
import { BEACON, NODE, VALIDATOR_CLIENT, VC } from '../../../constants' import { BEACON, NODE, VALIDATOR_CLIENT, VC } from '../../../constants'
import styles from './index.module.css'
const ConnectViaIP = () => { const ConnectViaIP = () => {
const [apiToken, setApiToken] = useState('') const [apiToken, setApiToken] = useState('')
const [isAdvanced, setIsAdvanced] = useState(false)
const { const {
isAdvanced,
beaconPort, beaconPort,
vcPort, vcPort,
nodeAddress, nodeAddress,
@ -19,16 +20,15 @@ const ConnectViaIP = () => {
vcAddress, vcAddress,
isBeaconSwitchOn, isBeaconSwitchOn,
isVcSwitchOn, isVcSwitchOn,
isBeaconChecked,
isVcChecked,
} = useSelector((state: RootState) => state.pairDevice) } = useSelector((state: RootState) => state.pairDevice)
const dispatch = useDispatch()
const changeApiToken = (value: string) => { const changeApiToken = (value: string) => {
setApiToken(value) setApiToken(value)
} }
const onAdvancedClickHandler = () => { const onAdvancedClickHandler = () => {
setIsAdvanced(state => !state) dispatch({ type: 'pairDevice/setIsAdvanced', payload: !isAdvanced })
} }
return ( return (
@ -47,24 +47,20 @@ const ConnectViaIP = () => {
</Button> </Button>
</XStack> </XStack>
{isAdvanced ? ( {isAdvanced ? (
<YStack space={'$3'}> <YStack space={'$3'} className={styles['rows-container']}>
<InputsRow <InputsRow
addressType={VALIDATOR_CLIENT} addressType={VALIDATOR_CLIENT}
portType={VC} portType={VC}
address={vcAddress} address={vcAddress}
port={vcPort} port={vcPort}
isAdvanced={isAdvanced}
isSwitchOn={isVcSwitchOn} isSwitchOn={isVcSwitchOn}
isChecked={isVcChecked}
/> />
<InputsRow <InputsRow
addressType={BEACON} addressType={BEACON}
portType={BEACON} portType={BEACON}
address={beaconAddress} address={beaconAddress}
port={beaconPort} port={beaconPort}
isAdvanced={isAdvanced}
isSwitchOn={isBeaconSwitchOn} isSwitchOn={isBeaconSwitchOn}
isChecked={isBeaconChecked}
/> />
</YStack> </YStack>
) : ( ) : (

View File

@ -1,16 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react' import type { Meta, StoryObj } from '@storybook/react'
import { withRouter } from 'storybook-addon-react-router-v6'
import InputsRow from './InputsRow' import InputsRow from './InputsRow'
import { import { DEFAULT_ADDRESS, NODE } from '../../../constants'
BEACON,
BEACON_PORT,
DEFAULT_ADDRESS,
NODE,
VALIDATOR_CLIENT,
VC,
VC_PORT,
} from '../../../constants'
const meta = { const meta = {
title: 'Pair Device/InputsRow', title: 'Pair Device/InputsRow',
@ -19,7 +10,6 @@ const meta = {
layout: 'centered', layout: 'centered',
}, },
tags: ['autodocs'], tags: ['autodocs'],
decorators: [withRouter],
} satisfies Meta<typeof InputsRow> } satisfies Meta<typeof InputsRow>
export default meta export default meta
@ -33,27 +23,3 @@ export const Node: Story = {
portType: '', 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

@ -1,31 +1,25 @@
import { Checkbox, Input, Text } from '@status-im/components' import { Input, Text } from '@status-im/components'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { Stack, Switch, XStack, YStack } from 'tamagui' import { Stack, Switch, YStack } from 'tamagui'
import { CheckIcon } from '@status-im/icons'
import { RootState } from '../../../redux/store' import { RootState } from '../../../redux/store'
import PortInput from './PortInput' import PortInput from './PortInput'
import { BEACON, VC } from '../../../constants' import { BEACON, VC } from '../../../constants'
import { isAddressValid, isPortValid } from '../../../utilities'
import styles from './index.module.css'
type InputsRowProps = { type InputsRowProps = {
addressType: string addressType: string
portType: string portType: string
isAdvanced?: boolean
address: string address: string
port: string port: string
isSwitchOn?: boolean isSwitchOn?: boolean
isChecked?: boolean isChecked?: boolean
} }
const InputsRow = ({ const InputsRow = ({ addressType, portType, address, port, isSwitchOn }: InputsRowProps) => {
isAdvanced, const { isAdvanced, beaconPort, vcPort, isNodeSwitchOn } = useSelector(
addressType,
portType,
address,
port,
isSwitchOn,
isChecked,
}: InputsRowProps) => {
const { beaconPort, vcPort, isNodeChecked, isNodeSwitchOn } = useSelector(
(state: RootState) => state.pairDevice, (state: RootState) => state.pairDevice,
) )
const dispatch = useDispatch() const dispatch = useDispatch()
@ -38,16 +32,20 @@ const InputsRow = ({
dispatch({ type: 'pairDevice/setIsSwitchOn', payload: { value, switchType: addressType } }) dispatch({ type: 'pairDevice/setIsSwitchOn', payload: { value, switchType: addressType } })
} }
const onCheckboxChange = (value: boolean) => {
dispatch({ type: 'pairDevice/setIsChecked', payload: { value, checkType: addressType } })
}
const onAddressChange = (value: string) => { const onAddressChange = (value: string) => {
dispatch({ type: 'pairDevice/setAddress', payload: { value, addressType } }) dispatch({ type: 'pairDevice/setAddress', payload: { value, addressType } })
} }
const isValidRow = () => {
if (isAdvanced) {
return isAddressValid(address) && isPortValid(port)
} else {
return isAddressValid(address) && isPortValid(vcPort) && isPortValid(beaconPort)
}
}
return ( return (
<XStack space={'$3'}> <div className={styles['row-container']}>
<YStack space={'$2'} flexBasis={0} flexGrow={2}> <YStack space={'$2'} flexBasis={0} flexGrow={2}>
<YStack> <YStack>
<Text size={13} color={'#647084'} weight={'semibold'}> <Text size={13} color={'#647084'} weight={'semibold'}>
@ -80,26 +78,23 @@ const InputsRow = ({
</Text> </Text>
<Input value={address} onChangeText={onAddressChange} /> <Input value={address} onChangeText={onAddressChange} />
</YStack> </YStack>
{isAdvanced ? ( {isAdvanced === true && <PortInput port={port} portType={portType} />}
<PortInput port={port} portType={portType} /> {isAdvanced === false && <PortInput port={vcPort} portType={VC} />}
) : ( {isAdvanced === false && <PortInput port={beaconPort} portType={BEACON} />}
<XStack space={'$3'} flexGrow={4} flexBasis={0}> <div style={{ display: 'flex', alignItems: 'end', marginBottom: '11px' }}>
<PortInput port={vcPort} portType={VC} /> <Stack flexBasis={0} flexGrow={0.5}>
<PortInput port={beaconPort} portType={BEACON} /> <CheckIcon
</XStack> size={16}
)} style={{
<div style={{ display: 'flex', alignItems: 'end', height: '100%' }}> borderRadius: '50%',
<Stack height={'46%'} flexBasis={0} flexGrow={0.5}> backgroundColor: isValidRow() ? '#2A4AF5' : '#1B273D1A',
<Checkbox padding: '1px',
id="AddressAndPortInputs" }}
variant="outline" color={'white'}
selected={isAdvanced ? isChecked : isNodeChecked}
onCheckedChange={onCheckboxChange}
size={20}
/> />
</Stack> </Stack>
</div> </div>
</XStack> </div>
) )
} }

View File

@ -19,7 +19,7 @@ const PortInput = ({ portType, port }: PortInputProps) => {
} }
return ( return (
<YStack space={'$2'} flexBasis={0} flexGrow={3}> <YStack space={'$2'} flexBasis={0} flexGrow={2}>
<Text size={13} color={'#647084'} weight={'semibold'}> <Text size={13} color={'#647084'} weight={'semibold'}>
{portType} Port {portType} Port
</Text> </Text>

View File

@ -0,0 +1,42 @@
.row-container {
display: flex;
gap: 8px;
}
@media (max-width: 1150px) and (min-width: 1000px) {
.row-container {
display: block;
}
.row-container > * {
margin-bottom: 8px;
}
.row-container > *:last-child {
margin-bottom: 0;
}
.rows-container {
display: flex;
gap: 10px;
}
}
@media (max-width: 500px) {
.row-container {
display: block;
}
.row-container > * {
margin-bottom: 8px;
}
.row-container > *:last-child {
margin-bottom: 0;
}
.rows-container {
display: flex;
gap: 10px;
}
}

View File

@ -1,6 +1,7 @@
import { NodeIcon, CompleteIdIcon, ConnectionIcon } from '@status-im/icons' import { NodeIcon, CompleteIdIcon, ConnectionIcon } from '@status-im/icons'
import { Label, Separator, XStack, YStack } from 'tamagui' import { Label, Separator, XStack, YStack } from 'tamagui'
import { useState } from 'react' import { useState } from 'react'
import { useSelector } from 'react-redux'
import { Button, Checkbox, Text } from '@status-im/components' import { Button, Checkbox, Text } from '@status-im/components'
import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow' import PageWrapperShadow from '../../components/PageWrappers/PageWrapperShadow'
@ -11,11 +12,16 @@ import CreateAvatar from '../../components/General/CreateAvatar/CreateAvatar'
import GenerateId from './GenerateId' import GenerateId from './GenerateId'
import Header from '../../components/General/Header' import Header from '../../components/General/Header'
import ConnectViaIP from './ConnectViaIP/ConnectViaIP' import ConnectViaIP from './ConnectViaIP/ConnectViaIP'
import { RootState } from '../../redux/store'
import { isAddressValid, isPortValid } from '../../utilities'
const PairDevice = () => { const PairDevice = () => {
const [isAwaitingPairing, setIsAwaitingPairing] = useState(false) const [isAwaitingPairing, setIsAwaitingPairing] = useState(false)
const [isConnectingViaIp, setIsConnectingViaIp] = useState(false) const [isConnectingViaIp, setIsConnectingViaIp] = useState(false)
const [isAutoConnectChecked, setIsAutoConnectChecked] = useState(false) const [isAutoConnectChecked, setIsAutoConnectChecked] = useState(false)
const { isAdvanced, nodeAddress, beaconAddress, beaconPort, vcAddress, vcPort } = useSelector(
(state: RootState) => state.pairDevice,
)
const isPaired = false const isPaired = false
const isPairing = false const isPairing = false
@ -29,6 +35,23 @@ const PairDevice = () => {
const continueHandler = () => {} const continueHandler = () => {}
const isDisabledButton = () => {
if (isConnectingViaIp) {
if (isAdvanced) {
return (
!isAddressValid(beaconAddress) ||
!isPortValid(beaconPort) ||
!isAddressValid(vcAddress) ||
!isPortValid(vcPort)
)
} else {
return !isAddressValid(nodeAddress) || !isPortValid(beaconPort) || !isPortValid(vcPort)
}
} else {
return !isPaired
}
}
return ( return (
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}> <PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
<YStack space={'$3'}> <YStack space={'$3'}>
@ -99,7 +122,7 @@ const PairDevice = () => {
<div> <div>
<Button <Button
icon={<NodeIcon size={20} />} icon={<NodeIcon size={20} />}
disabled={isConnectingViaIp ? false : !isPaired} disabled={isDisabledButton()}
onPress={continueHandler} onPress={continueHandler}
> >
{isConnectingViaIp ? 'Connect Device' : 'Continue'} {isConnectingViaIp ? 'Connect Device' : 'Continue'}

View File

@ -3,6 +3,7 @@ import { createSlice } from '@reduxjs/toolkit'
import { BEACON, BEACON_PORT, DEFAULT_ADDRESS, VALIDATOR_CLIENT, VC_PORT } from '../../constants' import { BEACON, BEACON_PORT, DEFAULT_ADDRESS, VALIDATOR_CLIENT, VC_PORT } from '../../constants'
type PairDeviceStateType = { type PairDeviceStateType = {
isAdvanced: boolean
beaconPort: string beaconPort: string
vcPort: string vcPort: string
nodeAddress: string nodeAddress: string
@ -11,12 +12,10 @@ type PairDeviceStateType = {
isNodeSwitchOn: boolean isNodeSwitchOn: boolean
isBeaconSwitchOn: boolean isBeaconSwitchOn: boolean
isVcSwitchOn: boolean isVcSwitchOn: boolean
isNodeChecked: boolean
isBeaconChecked: boolean
isVcChecked: boolean
} }
const initialState: PairDeviceStateType = { const initialState: PairDeviceStateType = {
isAdvanced: false,
beaconPort: BEACON_PORT, beaconPort: BEACON_PORT,
vcPort: VC_PORT, vcPort: VC_PORT,
nodeAddress: DEFAULT_ADDRESS, nodeAddress: DEFAULT_ADDRESS,
@ -25,15 +24,15 @@ const initialState: PairDeviceStateType = {
isNodeSwitchOn: true, isNodeSwitchOn: true,
isBeaconSwitchOn: true, isBeaconSwitchOn: true,
isVcSwitchOn: true, isVcSwitchOn: true,
isNodeChecked: true,
isBeaconChecked: true,
isVcChecked: true,
} }
const pairDeviceSlice = createSlice({ const pairDeviceSlice = createSlice({
name: 'pairDevice', name: 'pairDevice',
initialState, initialState,
reducers: { reducers: {
setIsAdvanced: (state, action) => {
state.isAdvanced = action.payload
},
setPort: (state, action) => { setPort: (state, action) => {
if (action.payload.portType === BEACON) { if (action.payload.portType === BEACON) {
state.beaconPort = action.payload.value state.beaconPort = action.payload.value
@ -59,15 +58,6 @@ const pairDeviceSlice = createSlice({
state.isNodeSwitchOn = action.payload.value 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
}
},
}, },
}) })

View File

@ -69,6 +69,18 @@ export const getHeightPercentages = (amountOfElements: number) => {
return `${percentages}%` return `${percentages}%`
} }
export const isAddressValid = (address: string) => {
return address.length > 0
}
export const isPortValid = (port: string) => {
if (port.length === 0) {
return false
}
return !isNaN(Number(port))
}
export const copyFunction = (text: string) => { export const copyFunction = (text: string) => {
navigator.clipboard.writeText(text) navigator.clipboard.writeText(text)
} }