Skip to content

Commit

Permalink
2.1.11 (#642)
Browse files Browse the repository at this point in the history
* use jazzicon for the navbar incon

* show node name in the navbar

* add ticket counter to strategies

* add icon to connect node

* make jazzicon apply styles in select only if its is turned on

* cleanup

* format

* formatg

* make icon generation better

* format

* format
  • Loading branch information
mjadach-iv authored Nov 27, 2024
1 parent 2a8ffbc commit fcadc06
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 54 deletions.
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ Builds the Node Admin.
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

### `yarn build-hub`

Builds the Staking Hub.
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

### `docker build --platform linux/amd64 -t europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin .`

Builds the Node Admin docker image with the name `node-admin`.
Expand Down
41 changes: 34 additions & 7 deletions src/components/ConnectNode/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from 'react';
import styled from '@emotion/styled';
import { Link, useNavigate } from 'react-router-dom';

Check warning on line 3 in src/components/ConnectNode/index.tsx

View workflow job for this annotation

GitHub Actions / Close release

'Link' is defined but never used
import { generateBase64Jazz } from '../../utils/functions';

// Components
import Modal from './modal';
Expand Down Expand Up @@ -38,8 +39,9 @@ const Container = styled(Button)`
margin-left: 8px;
width: 50px;
img {
height: 100%;
width: 100%;
height: 38px;
width: 38px;
border-radius: 50px;
}
}
`;
Expand All @@ -61,6 +63,10 @@ const NodeButton = styled.div`
color: #414141;
line-height: 12px;
}
.node-info-localname {
font-weight: 700;
color: #000050;
}
`;

const DropdownArrow = styled.img`
Expand Down Expand Up @@ -93,6 +99,12 @@ export default function ConnectNode() {
const openLoginModalToNode = useAppSelector((store) => store.auth.helper.openLoginModalToNode);
const peerId = useAppSelector((store) => store.node.addresses.data.hopr);
const localName = useAppSelector((store) => store.auth.loginData.localName);
const localNameToDisplay =
localName && localName.length > 17
? `${localName?.substring(0, 5)}${localName?.substring(localName.length - 11, localName.length)}`
: localName;
const apiEndpoint = useAppSelector((store) => store.auth.loginData.apiEndpoint);
const [nodeAddressIcon, set_nodeAddressIcon] = useState<string | null>(null);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); // State variable to hold the anchor element for the menu

const containerRef = useRef<HTMLButtonElement>(null);
Expand All @@ -111,6 +123,12 @@ export default function ConnectNode() {
};
}, []);

useEffect(() => {
if (!apiEndpoint) return;
const b64 = generateBase64Jazz(apiEndpoint);
if (b64) set_nodeAddressIcon(b64);
}, [apiEndpoint]);

useEffect(() => {
if (error) set_modalVisible(true);
}, [error]);
Expand Down Expand Up @@ -163,15 +181,24 @@ export default function ConnectNode() {
onClick={handleContainerClick}
ref={containerRef}
>
<div className="image-container">
<img src="/assets/hopr_logo.svg" />
<div
className="image-container"
id="jazz-icon-node"
>
<img
className={`${nodeAddressIcon && 'node-jazz-icon-present'}`}
src={nodeAddressIcon ?? '/assets/hopr_logo.svg'}
/>
</div>
{connected ? (
<>
<NodeButton>
<p className="node-info">
{peerId && `${peerId.substring(0, 6)}...${peerId.substring(peerId.length - 8, peerId.length)}`}
</p>
<span>
{localNameToDisplay && <p className="node-info node-info-localname">{localNameToDisplay}</p>}
<p className="node-info">
{peerId && `${peerId.substring(0, 6)}...${peerId.substring(peerId.length - 8, peerId.length)}`}
</p>
</span>
<div className="dropdown-icon">
<DropdownArrow src="/assets/dropdown-arrow.svg" />
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/ConnectNode/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ function ConnectNodeModal(props: ConnectNodeModalProps) {
style={{ width: '100%' }}
removeValue={clearSingleLocal}
removeValueTooltip={'Remove node from local storage'}
showJazzIcon
/>
<Tooltip title={'Clear all node credentials from the browser local storage'}>
<span>
Expand Down
79 changes: 54 additions & 25 deletions src/future-hopr-lib-components/Select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import FormControl from '@mui/material/FormControl';
import SelectMui, { SelectProps as SelectMuiProps } from '@mui/material/Select';
import { Tooltip, IconButton } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import { generateBase64Jazz } from '../../utils/functions';

const SFormControl = styled(FormControl)`
margin-bottom: 16px;
Expand All @@ -26,22 +27,40 @@ const SFormControl = styled(FormControl)`
display: none;
}
}
&.showJazzIcon {
.select-menu-item-text {
margin-left: 27px;
}
img.node-jazz-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
}
}
`;

interface Props extends SelectMuiProps {
removeValue?: (value: number) => void;
removeValueTooltip?: string;
showJazzIcon?: boolean;
values?: {
value: string | number;
name: string | number | null;
apiEndpoint: string | null;
disabled?: boolean;
}[];
native?: boolean;
}

const Select: React.FC<Props> = (props) => {
return (
<SFormControl style={props.style}>
<SFormControl
style={props.style}
className={`${props.showJazzIcon ? 'showJazzIcon' : ''}`}
>
<InputLabel id="select-small">{props.label}</InputLabel>
<SelectMui
labelId="select-small"
Expand All @@ -55,30 +74,40 @@ const Select: React.FC<Props> = (props) => {
MenuProps={{ disableScrollLock: true }}
>
{props.values &&
props.values.map((elem, index) => (
<MenuItem
value={elem.value}
disabled={elem.disabled}
key={`${elem.value}_${elem.name}_${index}`}
style={props.removeValue && { justifyContent: 'space-between' }}
>
{elem.name}
{props.removeValue && (
<Tooltip title={props.removeValueTooltip}>
<IconButton
aria-label="delete"
className="removeValue"
onClick={(event) => {
event.stopPropagation();
props?.removeValue?.(Number(elem.value));
}}
>
<DeleteIcon />
</IconButton>
</Tooltip>
)}
</MenuItem>
))}
props.values.map((elem, index) => {
const icon = elem.apiEndpoint && generateBase64Jazz(elem.apiEndpoint);
return (
<MenuItem
value={elem.value}
disabled={elem.disabled}
key={`${elem.value}_${elem.name}_${index}`}
id={`${elem.value}_${elem.name}_${index}`}
style={props.removeValue && { justifyContent: 'space-between' }}
>
{props.showJazzIcon && (
<img
className={`node-jazz-icon ${icon && 'node-jazz-icon-present'}`}
src={icon ?? '/assets/hopr_logo.svg'}
/>
)}
<span className="select-menu-item-text">{elem.name}</span>
{props.removeValue && (
<Tooltip title={props.removeValueTooltip}>
<IconButton
aria-label="delete"
className="removeValue"
onClick={(event) => {
event.stopPropagation();
props?.removeValue?.(Number(elem.value));
}}
>
<DeleteIcon />
</IconButton>
</Tooltip>
)}
</MenuItem>
);
})}
</SelectMui>
</SFormControl>
);
Expand Down
15 changes: 15 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,18 @@ li.selected-safe {
.inline {
display: inline;
}

img.node-jazz-icon {
margin-right: 10px;
border-radius: 30px;
height: 22px;
width: 22px;
}

img.node-jazz-icon-present {
background: rgb(3, 94, 91);
}

span.select-menu-item-text {
flex-grow: 1;
}
113 changes: 110 additions & 3 deletions src/pages/node/configuration.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useEffect, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../../store';
import { nodeActionsAsync } from '../../store/slices/node';

// HOPR Components
import { SubpageTitle } from '../../components/SubpageTitle';
Expand All @@ -24,6 +23,8 @@ function SettingsPage() {
const dispatch = useAppDispatch();
const prevNotificationSettings = useAppSelector((store) => store.app.configuration.notifications);
const strategies = useAppSelector((store) => store.node.configuration.data?.hopr?.strategy);
const ticketPrice = useAppSelector((store) => store.node.ticketPrice.data);
const [strategiesString, set_strategiesString] = useState<string | null>(null);
const [localNotificationSettings, set_localNotificationSettings] = useState<typeof prevNotificationSettings>();

useEffect(() => {
Expand All @@ -32,6 +33,112 @@ function SettingsPage() {
}
}, [prevNotificationSettings]);

useEffect(() => {
if (strategies) {
let tmp = JSON.stringify(strategies, null, 2);

try {
if (ticketPrice) {
// min_stake_threshold
if (strategies?.strategies?.AutoFunding?.min_stake_threshold) {
const key = 'min_stake_threshold';
const min_stake_threshold = strategies.strategies.AutoFunding[key].replace(' HOPR', '');
const min_stake_thresholdBigInt = BigInt(min_stake_threshold) * BigInt(1e18);
const ticketBigInt = BigInt(ticketPrice);
const ticketsBigInt = min_stake_thresholdBigInt / ticketBigInt;
const ticketsString = ticketsBigInt.toString();
const stringToReplace = `"${key}": "${strategies.strategies.AutoFunding[key]}"`;
if (tmp.includes(stringToReplace + ',')) {
tmp = tmp.replace(
stringToReplace + ',',
`"${key}": "${strategies.strategies.AutoFunding[key]}", // tickets: ${ticketsString}`,
);
} else {
tmp = tmp.replace(
stringToReplace,
`"${key}": "${strategies.strategies.AutoFunding[key]}" // tickets: ${ticketsString}`,
);
}
}

// funding_amount
if (strategies?.strategies?.AutoFunding?.funding_amount) {
const key = 'funding_amount';
const funding_amount = strategies.strategies.AutoFunding[key].replace(' HOPR', '');
const funding_amountBigInt = BigInt(funding_amount) * BigInt(1e18);
const ticketBigInt = BigInt(ticketPrice);
const ticketsBigInt = funding_amountBigInt / ticketBigInt;
const ticketsString = ticketsBigInt.toString();
const stringToReplace = `"${key}": "${strategies.strategies.AutoFunding[key]}"`;
if (tmp.includes(stringToReplace + ',')) {
tmp = tmp.replace(
stringToReplace + ',',
`"${key}": "${strategies.strategies.AutoFunding[key]}", // tickets: ${ticketsString}`,
);
} else {
tmp = tmp.replace(
stringToReplace,
`"${key}": "${strategies.strategies.AutoFunding[key]}" // tickets: ${ticketsString}`,
);
}
}

// minimum_redeem_ticket_value
if (strategies?.strategies?.AutoRedeeming?.minimum_redeem_ticket_value) {
const key = 'minimum_redeem_ticket_value';
const minimum_redeem_ticket_value = strategies.strategies.AutoRedeeming[key].replace(' HOPR', '');
const minimum_redeem_ticket_valueBigInt = BigInt(minimum_redeem_ticket_value) * BigInt(1e18);
const ticketBigInt = BigInt(ticketPrice);
const ticketsBigInt = minimum_redeem_ticket_valueBigInt / ticketBigInt;
const ticketsString = ticketsBigInt.toString();
const stringToReplace = `"${key}": "${strategies.strategies.AutoRedeeming[key]}"`;
if (tmp.includes(stringToReplace + ',')) {
tmp = tmp.replace(
stringToReplace + ',',
`"${key}": "${strategies.strategies.AutoRedeeming[key]}", // tickets: ${ticketsString}`,
);
} else {
tmp = tmp.replace(
stringToReplace,
`"${key}": "${strategies.strategies.AutoRedeeming[key]}" // tickets: ${ticketsString}`,
);
}
}

// on_close_redeem_single_tickets_value_min
if (strategies?.strategies?.AutoRedeeming?.on_close_redeem_single_tickets_value_min) {
const key = 'on_close_redeem_single_tickets_value_min';
const on_close_redeem_single_tickets_value_min = strategies.strategies.AutoRedeeming[key].replace(
' HOPR',
'',
);
const on_close_redeem_single_tickets_value_minBigInt =
BigInt(on_close_redeem_single_tickets_value_min) * BigInt(1e18);
const ticketBigInt = BigInt(ticketPrice);
const ticketsBigInt = on_close_redeem_single_tickets_value_minBigInt / ticketBigInt;
const ticketsString = ticketsBigInt.toString();
const stringToReplace = `"${key}": "${strategies.strategies.AutoRedeeming[key]}"`;
if (tmp.includes(stringToReplace + ',')) {
tmp = tmp.replace(
stringToReplace + ',',
`"${key}": "${strategies.strategies.AutoRedeeming[key]}", // tickets: ${ticketsString}`,
);
} else {
tmp = tmp.replace(
stringToReplace,
`"${key}": "${strategies.strategies.AutoRedeeming[key]}" // tickets: ${ticketsString}`,
);
}
}
}
} catch (e) {
console.warn('Error while counting strategies against current ticket price.', e);
}

set_strategiesString(tmp);
}
}, [strategies, ticketPrice]);

const handleSaveSettings = async () => {
if (localNotificationSettings) {
dispatch(appActions.setNotificationSettings(localNotificationSettings));
Expand Down Expand Up @@ -131,9 +238,9 @@ function SettingsPage() {
<tr>
<th>Strategies</th>
<td>
{strategies && (
{strategiesString && (
<CodeCopyBox
code={JSON.stringify(strategies, null, 2)}
code={strategiesString}
breakSpaces
/>
)}
Expand Down
Loading

0 comments on commit fcadc06

Please sign in to comment.