Skip to content

Commit

Permalink
Add rewards today tooltip (#150)
Browse files Browse the repository at this point in the history
* Add rewards today tooltip

* Remove staked amount block and add current balance breakdown

* Show notification and modal on first staking

* Move colors to constants, review fixes

---------

Co-authored-by: Atatakai <[email protected]>
  • Loading branch information
Tanya-atatakai and Atatakai authored Jun 3, 2024
1 parent 6156813 commit c588be8
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 77 deletions.
2 changes: 1 addition & 1 deletion electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ const createMainWindow = () => {
mainWindow.setSize(width, height);
});

ipcMain.on('show-notification', (title, description) => {
ipcMain.on('show-notification', (_event, title, description) => {
showNotification(title, description || undefined);
});

Expand Down
4 changes: 3 additions & 1 deletion frontend/components/Main/KeepAgentRunning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { CardSection } from '../styled/CardSection';

const { Text } = Typography;

const COVER_BLOCK_BORDERS_STYLE = { marginBottom: '-1px' };

export const KeepAgentRunning = () => {
const { storeState } = useStore();
const { serviceStatus } = useServices();
Expand All @@ -17,7 +19,7 @@ export const KeepAgentRunning = () => {
if (serviceStatus !== DeploymentStatus.DEPLOYED) return null;

return (
<CardSection>
<CardSection style={COVER_BLOCK_BORDERS_STYLE}>
<Alert
type="info"
fullWidth
Expand Down
82 changes: 75 additions & 7 deletions frontend/components/Main/MainHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Badge, Button, Flex, Popover, Typography } from 'antd';
import { Badge, Button, Flex, Modal, Popover, Typography } from 'antd';
import { formatUnits } from 'ethers/lib/utils';
import Image from 'next/image';
import { useCallback, useEffect, useMemo, useState } from 'react';
Expand All @@ -8,23 +8,72 @@ import { Chain, DeploymentStatus } from '@/client';
import { COLOR, LOW_BALANCE, SERVICE_TEMPLATES } from '@/constants';
import { useBalance, useServiceTemplates } from '@/hooks';
import { useElectronApi } from '@/hooks/useElectronApi';
import { useReward } from '@/hooks/useReward';
import { useServices } from '@/hooks/useServices';
import { useStore } from '@/hooks/useStore';
import { useWallet } from '@/hooks/useWallet';
import { ServicesService } from '@/service';
import { WalletService } from '@/service/Wallet';

const { Text } = Typography;
const { Text, Title, Paragraph } = Typography;

const LOADING_MESSAGE =
"It may take a while to start your agent, so feel free to close the app. We'll notify you once your agent is running.";

enum ServiceButtonLoadingState {
Starting,
Pausing,
NotLoading,
}

const FirstRunModal = ({
open,
onClose,
}: {
open: boolean;
onClose: () => void;
}) => {
const { minimumStakedAmountRequired } = useReward();

if (!open) return null;
return (
<Modal
open={open}
width={412}
onCancel={onClose}
footer={[
<Button
key="ok"
type="primary"
block
size="large"
className="mt-8"
onClick={onClose}
>
Got it
</Button>,
]}
>
<Flex align="center" justify="center">
<Image
src="/splash-robot-head.png"
width={100}
height={100}
alt="OLAS logo"
/>
</Flex>
<Title level={5} className="mt-12 text-center">
{`Your agent is running and you&apos;ve staked ${minimumStakedAmountRequired} OLAS!`}
</Title>
<Paragraph>Your agent is working towards earning rewards.</Paragraph>
<Paragraph>
Pearl is designed to make it easy for you to earn staking rewards every
day. Simply leave the app and agent running in the background for ~1hr a
day.
</Paragraph>
</Modal>
);
};

export const MainHeader = () => {
const { storeState } = useStore();
const { services, serviceStatus, setServiceStatus } = useServices();
Expand All @@ -39,6 +88,11 @@ export const MainHeader = () => {
setIsPaused: setIsBalancePollingPaused,
} = useBalance();

const [isModalOpen, setIsModalOpen] = useState(false);
const handleModalClose = useCallback(() => setIsModalOpen(false), []);

const { minimumStakedAmountRequired } = useReward();

const safeOlasBalanceWithStaked = useMemo(() => {
if (safeBalance?.OLAS === undefined) return;
if (totalOlasStakedBalance === undefined) return;
Expand Down Expand Up @@ -115,14 +169,23 @@ export const MainHeader = () => {
// });
// }

const serviceExists = !!services?.[0];

// For now POST /api/services will take care of creating, starting and updating the service
return ServicesService.createService({
serviceTemplate,
deploy: true,
})
.then(() => {
setServiceStatus(DeploymentStatus.DEPLOYED);
showNotification?.('Your agent is now running!');
if (serviceExists) {
showNotification?.('Your agent is now running!');
} else {
showNotification?.(
`Your agent is running and you've staked ${minimumStakedAmountRequired} OLAS!`,
);
setIsModalOpen(true);
}
})
.finally(() => {
setIsBalancePollingPaused(false);
Expand All @@ -134,11 +197,13 @@ export const MainHeader = () => {
}
}, [
masterSafeAddress,
minimumStakedAmountRequired,
serviceTemplate,
services,
setIsBalancePollingPaused,
setServiceStatus,
wallets,
showNotification,
wallets,
]);

const handlePause = useCallback(() => {
Expand Down Expand Up @@ -250,17 +315,19 @@ export const MainHeader = () => {
);
})();

const serviceExists = !!services?.[0];

if (!isDeployable) {
return (
<Button type="default" size="large" disabled>
Start agent
Start agent {!serviceExists && '& stake'}
</Button>
);
}

return (
<Button type="primary" size="large" onClick={handleStart}>
Start agent
Start agent {!serviceExists && '& stake'}
</Button>
);
}, [
Expand All @@ -279,6 +346,7 @@ export const MainHeader = () => {
<Flex justify="start" align="center" gap={10}>
{agentHead}
{serviceToggleButton}
<FirstRunModal open={isModalOpen} onClose={handleModalClose} />
</Flex>
);
};
101 changes: 96 additions & 5 deletions frontend/components/Main/MainOlasBalance.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,104 @@
import { Skeleton } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import { Flex, Skeleton, Tooltip, Typography } from 'antd';
import { useMemo } from 'react';
import styled from 'styled-components';

import { balanceFormat } from '@/common-util/numberFormatters';
import { COLOR } from '@/constants';
import { UNICODE_SYMBOLS } from '@/constants/unicode';
import { useBalance } from '@/hooks';
import { useReward } from '@/hooks/useReward';

import { CardSection } from '../styled/CardSection';

const { Text } = Typography;
const Balance = styled.span`
letter-spacing: -2px;
margin-right: 4px;
`;
const BalanceBreakdown = styled.div`
padding: 4px;
`;
const BalanceBreakdownLine = styled.div`
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: ${COLOR.TEXT};
> span {
background: ${COLOR.WHITE};
z-index: 1;
&:first-child {
padding-right: 6px;
}
&:last-child {
padding-left: 6px;
}
}
&:before {
content: '';
position: absolute;
bottom: 6px;
width: 100%;
border-bottom: 2px dotted ${COLOR.BORDER_GRAY};
}
&:not(:last-child) {
margin-bottom: 8px;
}
`;
const OVERLAY_STYLE = { maxWidth: '300px', width: '300px' };

const CurrentBalance = () => {
const { totalOlasBalance, totalOlasStakedBalance } = useBalance();
const { accruedServiceStakingRewards } = useReward();

const balances = useMemo(() => {
return [
{
title: 'Staked amount',
value: balanceFormat(totalOlasStakedBalance ?? 0, 2),
},
{
title: 'Unclaimed rewards',
value: balanceFormat(accruedServiceStakingRewards ?? 0, 2),
},
{
title: 'Unused funds',
value: balanceFormat(
(totalOlasBalance ?? 0) - (totalOlasStakedBalance ?? 0),
2,
),
},
];
}, [accruedServiceStakingRewards, totalOlasBalance, totalOlasStakedBalance]);

return (
<Text type="secondary">
Current balance&nbsp;
<Tooltip
arrow={false}
placement="bottom"
overlayStyle={OVERLAY_STYLE}
title={
<BalanceBreakdown>
{balances.map((item, index) => (
<BalanceBreakdownLine key={index}>
<span>{item.title}</span>
<span className="font-weight-600">{item.value} OLAS</span>
</BalanceBreakdownLine>
))}
</BalanceBreakdown>
}
>
<InfoCircleOutlined />
</Tooltip>
</Text>
);
};

export const MainOlasBalance = () => {
const { isBalanceLoaded, totalOlasBalance } = useBalance();
Expand All @@ -21,12 +109,15 @@ export const MainOlasBalance = () => {
}, [totalOlasBalance]);

return (
<CardSection align="end" gap={5} bordertop="true" borderbottom="true">
<CardSection vertical gap={8} bordertop="true" borderbottom="true">
{isBalanceLoaded ? (
<>
<span className="balance-symbol">{UNICODE_SYMBOLS.OLAS}</span>
<Balance className="balance">{balance}</Balance>
<span className="balance-currency">OLAS</span>
<CurrentBalance />
<Flex align="end">
<span className="balance-symbol">{UNICODE_SYMBOLS.OLAS}</span>
<Balance className="balance">{balance}</Balance>
<span className="balance-currency">OLAS</span>
</Flex>
</>
) : (
<Skeleton.Input active size="large" style={{ margin: '4px 0' }} />
Expand Down
Loading

0 comments on commit c588be8

Please sign in to comment.