Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into mohan/improve-update-…
Browse files Browse the repository at this point in the history
…experience
  • Loading branch information
truemiller committed Jul 17, 2024
2 parents 628e321 + 2b13bc2 commit 3f67622
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 55 deletions.
10 changes: 8 additions & 2 deletions frontend/components/Main/MainHeader/FirstRunModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import { Button, Flex, Modal, Typography } from 'antd';
import Image from 'next/image';
import { FC } from 'react';

import { useReward } from '@/hooks/useReward';
import { useServiceTemplates } from '@/hooks/useServiceTemplates';
import { getMinimumStakedAmountRequired } from '@/utils/service';

const { Title, Paragraph } = Typography;

type FirstRunModalProps = { open: boolean; onClose: () => void };

export const FirstRunModal: FC<FirstRunModalProps> = ({ open, onClose }) => {
const { minimumStakedAmountRequired } = useReward();
const { getServiceTemplates } = useServiceTemplates();

if (!open) return null;

const minimumStakedAmountRequired = getMinimumStakedAmountRequired(
getServiceTemplates()[0],
);

return (
<Modal
open={open}
Expand Down
31 changes: 24 additions & 7 deletions frontend/components/Main/MainHeader/index.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, Popover, Skeleton, Typography } from 'antd';
import Image from 'next/image';
import { useCallback, useEffect, useMemo, useState } from 'react';

Expand All @@ -8,15 +8,16 @@ import { COLOR } from '@/constants/colors';
import { LOW_BALANCE } from '@/constants/thresholds';
import { useBalance } from '@/hooks/useBalance';
import { useElectronApi } from '@/hooks/useElectronApi';
import { useReward } from '@/hooks/useReward';
import { useServices } from '@/hooks/useServices';
import { useServiceTemplates } from '@/hooks/useServiceTemplates';
import { useStakingContractInfo } from '@/hooks/useStakingContractInfo';
import { useStore } from '@/hooks/useStore';
import { useWallet } from '@/hooks/useWallet';
import { ServicesService } from '@/service/Services';
import { WalletService } from '@/service/Wallet';
import { getMinimumStakedAmountRequired } from '@/utils/service';

import { CannotStartAgent } from './CannotStartAgent';
import { requiredGas, requiredOlas } from './constants';
import { FirstRunModal } from './FirstRunModal';

Expand Down Expand Up @@ -85,9 +86,8 @@ export const MainHeader = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const handleModalClose = useCallback(() => setIsModalOpen(false), []);

const { minimumStakedAmountRequired } = useReward();

const { canStartAgent } = useStakingContractInfo();
const { isInitialStakingLoad, isAgentEvicted, canStartAgent } =
useStakingContractInfo();

// hook to setup tray icon
useSetupTrayIcon();
Expand Down Expand Up @@ -170,6 +170,9 @@ export const MainHeader = () => {
if (serviceExists) {
showNotification?.('Your agent is now running!');
} else {
const minimumStakedAmountRequired =
getMinimumStakedAmountRequired(serviceTemplate);

showNotification?.(
`Your agent is running and you've staked ${minimumStakedAmountRequired} OLAS!`,
);
Expand All @@ -186,7 +189,6 @@ export const MainHeader = () => {
}
}, [
masterSafeAddress,
minimumStakedAmountRequired,
serviceTemplate,
services,
setIsBalancePollingPaused,
Expand All @@ -206,6 +208,16 @@ export const MainHeader = () => {
}, [services, setServiceStatus]);

const serviceToggleButton = useMemo(() => {
if (!canStartAgent) return <CannotStartAgent />;

if (canStartAgent && isAgentEvicted) {
return (
<Button type="primary" size="large" onClick={handleStart}>
Start agent
</Button>
);
}

if (serviceButtonState === ServiceButtonLoadingState.Pausing) {
return (
<Button type="default" size="large" ghost disabled loading>
Expand Down Expand Up @@ -294,12 +306,17 @@ export const MainHeader = () => {
storeState?.isInitialFunded,
totalEthBalance,
canStartAgent,
isAgentEvicted,
]);

return (
<Flex justify="start" align="center" gap={10}>
{agentHead}
{serviceToggleButton}
{isInitialStakingLoad ? (
<Skeleton.Input style={{ width: 80 }} active />
) : (
serviceToggleButton
)}
<FirstRunModal open={isModalOpen} onClose={handleModalClose} />
</Flex>
);
Expand Down
32 changes: 15 additions & 17 deletions frontend/components/Main/MainNeedsFunds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Flex, Typography } from 'antd';
import { formatUnits } from 'ethers/lib/utils';
import { ReactNode, useEffect, useMemo } from 'react';

import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates';
import { UNICODE_SYMBOLS } from '@/constants/symbols';
import { useBalance } from '@/hooks/useBalance';
import { useElectronApi } from '@/hooks/useElectronApi';
import { useServiceTemplates } from '@/hooks/useServiceTemplates';
import { useStore } from '@/hooks/useStore';
import { getMinimumStakedAmountRequired } from '@/utils/service';

import { Alert } from '../Alert';
import { CardSection } from '../styled/CardSection';
Expand All @@ -15,7 +16,13 @@ const { Text, Paragraph } = Typography;
const COVER_PREV_BLOCK_BORDER_STYLE = { marginTop: '-1px' };

const useNeedsFunds = () => {
const serviceTemplate = SERVICE_TEMPLATES[0];
const { getServiceTemplates } = useServiceTemplates();

const serviceTemplate = useMemo(
() => getServiceTemplates()[0],
[getServiceTemplates],
);

const { storeState } = useStore();
const { safeBalance, totalOlasStakedBalance } = useBalance();

Expand All @@ -25,24 +32,15 @@ const useNeedsFunds = () => {
const monthlyGasEstimate = Number(
formatUnits(`${serviceTemplate.configuration.monthly_gas_estimate}`, 18),
);
const olasCostOfBond = Number(
formatUnits(`${serviceTemplate.configuration.olas_cost_of_bond}`, 18),
);
const olasRequiredToStake = Number(
formatUnits(
`${serviceTemplate.configuration.olas_required_to_stake}`,
18,
),
);

const minimumStakedAmountRequired =
getMinimumStakedAmountRequired(serviceTemplate);

return {
eth: monthlyGasEstimate,
olas: olasCostOfBond + olasRequiredToStake,
olas: minimumStakedAmountRequired,
};
}, [
serviceTemplate.configuration.monthly_gas_estimate,
serviceTemplate.configuration.olas_cost_of_bond,
serviceTemplate.configuration.olas_required_to_stake,
]);
}, [serviceTemplate]);

const hasEnoughEthForInitialFunding = useMemo(
() => (safeBalance?.ETH || 0) >= (serviceFundRequirements?.eth || 0),
Expand Down
127 changes: 126 additions & 1 deletion frontend/components/Main/MainRewards.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Flex, Skeleton, Tag, Tooltip, Typography } from 'antd';
import { Button, Flex, Modal, Skeleton, Tag, Tooltip, Typography } from 'antd';
import Image from 'next/image';
import { useCallback, useEffect, useRef, useState } from 'react';

import { useBalance } from '@/hooks/useBalance';
import { useReward } from '@/hooks/useReward';
Expand Down Expand Up @@ -56,3 +58,126 @@ export const MainRewards = () => {
</CardSection>
);
};

const SHARE_TEXT = `I just earned my first reward through the Operate app powered by #olas!\n\nDownload the Pearl app:`;
const OPERATE_URL = 'https://olas.network/operate?pearl=first-reward';

const NotifyRewards = () => {
const { isEligibleForRewards, availableRewardsForEpochEth } = useReward();
const { totalOlasBalance } = useBalance();
const { showNotification, store } = useElectronApi();
const { storeState } = useStore();

const [canShowNotification, setCanShowNotification] = useState(false);

// hook to set the flag to show the notification
useEffect(() => {
if (!isEligibleForRewards) return;
if (!storeState) return;
if (storeState?.firstRewardNotificationShown) return;
if (!availableRewardsForEpochEth) return;

setCanShowNotification(true);
}, [
isEligibleForRewards,
availableRewardsForEpochEth,
showNotification,
storeState,
]);

// hook to show desktop app notification
useEffect(() => {
if (!canShowNotification) return;

showNotification?.(
'Your agent earned its first staking rewards!',
`Congratulations! Your agent just got the first reward for you! Your current balance: ${availableRewardsForEpochEth} OLAS`,
);
}, [canShowNotification, availableRewardsForEpochEth, showNotification]);

const closeNotificationModal = useCallback(() => {
setCanShowNotification(false);

// once the notification is closed, set the flag to true
store?.set?.('firstRewardNotificationShown', true);
}, [store]);

const onTwitterShare = useCallback(() => {
const encodedText = encodeURIComponent(SHARE_TEXT);
const encodedURL = encodeURIComponent(OPERATE_URL);

window.open(
`https://twitter.com/intent/tweet?text=${encodedText}&url=${encodedURL}`,
'_blank',
);
}, []);

if (!canShowNotification) return null;

return (
<Modal
open={canShowNotification}
width={400}
onCancel={closeNotificationModal}
footer={[
<Button
key="back"
type="primary"
block
size="large"
className="mt-8"
onClick={onTwitterShare}
>
<Flex align="center" justify="center" gap={2}>
Share on
<Image
src="/twitter.svg"
width={24}
height={24}
alt="Share on twitter"
/>
</Flex>
</Button>,
]}
>
<ConfettiAnimation />

<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">
Your agent just earned the first reward!
</Title>

<Flex vertical gap={16}>
<Text>
Congratulations! Your agent just earned the first
<Text strong>
{` ${balanceFormat(availableRewardsForEpochEth, 2)} OLAS `}
</Text>
for you!
</Text>

<Text>
Your current balance:
<Text strong>{` ${balanceFormat(totalOlasBalance, 2)} OLAS `}</Text>
</Text>

<Text>Keep it running to get even more!</Text>
</Flex>
</Modal>
);
};

export const MainRewards = () => (
<>
<DisplayRewards />
<NotifyRewards />
</>
);
4 changes: 0 additions & 4 deletions frontend/context/RewardProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ export const RewardProvider = ({ children }: PropsWithChildren) => {
const [availableRewardsForEpoch, setAvailableRewardsForEpoch] =
useState<number>();
const [isEligibleForRewards, setIsEligibleForRewards] = useState<boolean>();
const [minimumStakedAmountRequired, setMinimumStakedAmountRequired] =
useState<number>();

const availableRewardsForEpochEth = useMemo<number | undefined>(() => {
if (!availableRewardsForEpoch) return;
Expand Down Expand Up @@ -87,7 +85,6 @@ export const RewardProvider = ({ children }: PropsWithChildren) => {
setAccruedServiceStakingRewards(
stakingRewardsInfo?.accruedServiceStakingRewards,
);
setMinimumStakedAmountRequired(stakingRewardsInfo?.minimumStakedAmount);
setAvailableRewardsForEpoch(rewards);
}, [service]);

Expand All @@ -114,7 +111,6 @@ export const RewardProvider = ({ children }: PropsWithChildren) => {
availableRewardsForEpochEth,
isEligibleForRewards,
optimisticRewardsEarnedForEpoch,
minimumStakedAmountRequired,
updateRewards,
}}
>
Expand Down
Loading

0 comments on commit 3f67622

Please sign in to comment.