Skip to content

Commit

Permalink
Claw back notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
rifeljm committed Oct 4, 2023
1 parent 488288a commit 70cbeae
Show file tree
Hide file tree
Showing 17 changed files with 493 additions and 67 deletions.
1 change: 1 addition & 0 deletions packages/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export { default as useTrans } from './useTrans';
export { default as useValidateChangePassphraseParams } from './useValidateChangePassphraseParams';
export { default as useWalletThemeColor } from './useWalletThemeColor';
export { default as useAddressBook } from './useAddressBook';
export { default as useGetTextFromTransaction } from './useGetTextFromTransaction';
81 changes: 81 additions & 0 deletions packages/core/src/hooks/useGetTextFromTransaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useGetAutoClaimQuery, useGetTimestampForHeightQuery, useGetHeightInfoQuery } from '@chia-network/api-react';
import { defineMessage } from '@lingui/macro';
import moment from 'moment';

import useTrans from './useTrans';

function getTextFromTransaction(
transactionRow: any,
t: any,
lastBlockTimeStamp: number,
isAutoClaimEnabled: any,
isGetHeightInfoLoading: boolean,
isGetTimestampForHeightLoading: boolean
) {
let text = '';
const canBeClaimedAt = moment((transactionRow?.timestamp || 0) * 1000);
if (transactionRow?.timeLock) {
canBeClaimedAt.add(transactionRow.timeLock, 'seconds');
}
const currentTime = moment.unix(lastBlockTimeStamp - 20); // extra 20 seconds so if the auto claim is enabled, it will not show to button to claim it
const timeLeft = canBeClaimedAt.diff(currentTime, 'seconds');
if (isGetHeightInfoLoading || isGetTimestampForHeightLoading || !lastBlockTimeStamp || transactionRow.claimed)
return null;
if (timeLeft > 0 && !transactionRow.passedTimeLock) {
text = isAutoClaimEnabled
? t(
defineMessage({
message: 'Will be autoclaimed in ',
})
)
: t(
defineMessage({
message: 'Can be claimed in ',
})
);
text += canBeClaimedAt.from(currentTime, true); // ... 3 days
} else if (transactionRow?.sent === 0) {
text = t(
defineMessage({
message: 'Claim transaction',
})
);
} else {
text = t(
defineMessage({
message: 'Claiming...',
})
);
}
return text;
}

export default function useGetTextFromTransaction(notification: any) {
const { data: height, isLoading: isGetHeightInfoLoading } = useGetHeightInfoQuery(undefined, {
pollingInterval: 3000,
});

const { data: lastBlockTimeStampData, isLoading: isGetTimestampForHeightLoading } = useGetTimestampForHeightQuery({
height: height || 0,
});

const { data: autoClaimData, isLoading: isGetAutoClaimLoading } = useGetAutoClaimQuery();
const isAutoClaimEnabled = !isGetAutoClaimLoading && autoClaimData?.enabled;

let lastBlockTimeStamp: number = 0;

if (!isGetTimestampForHeightLoading) {
lastBlockTimeStamp = lastBlockTimeStampData?.timestamp || 0;
}

const t = useTrans();

return getTextFromTransaction(
notification,
t,
lastBlockTimeStamp,
isAutoClaimEnabled,
isGetHeightInfoLoading,
isGetTimestampForHeightLoading
);
}
8 changes: 7 additions & 1 deletion packages/gui/src/@types/Notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export type NotificationAnnouncement = NotificationBase & {
url?: string;
};

type Notification = NotificationOffer | NotificationCounterOffer | NotificationAnnouncement;
export type NotificationClawback = NotificationBase & {
type: NotificationType.INCOMING_CLAWBACK_RECEIVE;
amount: number;
timeLock: number;
sent: number;
};

type Notification = NotificationOffer | NotificationCounterOffer | NotificationAnnouncement | NotificationClawback;
export default Notification;
3 changes: 3 additions & 0 deletions packages/gui/src/components/app/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Farm from '../farm/Farm';
import FullNode from '../fullNode/FullNode';
import Harvest from '../harvest/Harvest';
import NFTs from '../nfts/NFTs';
import NotificationHistory from '../notification/NotificationHistory';
import { CreateOffer } from '../offers/OfferManager';
import Plot from '../plot/Plot';
import Pool from '../pool/Pool';
Expand Down Expand Up @@ -45,6 +46,7 @@ export default function AppRouter() {
<Route path="dashboard/*" element={<Navigate to="wallets" />} />
<Route path="dashboard/settings/*" element={<Settings />} />
<Route path="dashboard/addressbook/*" element={<AddressBook />} />
<Route path="dashboard/history/*" element={<NotificationHistory />} />
</Route>
) : (
<Route element={<LayoutDashboard sidebar={<DashboardSideBar />} actions={<AppStatusHeader />} outlet />}>
Expand All @@ -60,6 +62,7 @@ export default function AppRouter() {
<Route path="dashboard/farm/*" element={<Farm />} />
<Route path="dashboard/pool/*" element={<Pool />} />
<Route path="dashboard/addressbook/*" element={<AddressBook />} />
<Route path="dashboard/history/*" element={<NotificationHistory />} />
</Route>
)}
</Route>
Expand Down
5 changes: 5 additions & 0 deletions packages/gui/src/components/notification/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type NotificationData from '../../@types/Notification';
import NotificationType from '../../constants/NotificationType';

import NotificationAnnouncement from './NotificationAnnouncement';
import NotificationClawbackTransaction from './NotificationClawbackTransaction';
import NotificationOffer from './NotificationOffer';

export type NotificationProps = {
Expand All @@ -22,5 +23,9 @@ export default function Notification(props: NotificationProps) {
return <NotificationAnnouncement notification={notification} onClick={onClick} />;
}

if (notification.type === NotificationType.INCOMING_CLAWBACK_RECEIVE) {
return <NotificationClawbackTransaction notification={notification} onClick={onClick} />;
}

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useGetAutoClaimQuery, useGetTimestampForHeightQuery, useGetHeightInfoQuery } from '@chia-network/api-react';
import { Flex, MojoToChia, useTrans, useGetTextFromTransaction } from '@chia-network/core';
import { Trans } from '@lingui/macro';
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import { Typography } from '@mui/material';
import React from 'react';
import { useNavigate } from 'react-router-dom';

import HumanTimestamp from '../helpers/HumanTimestamp';

import NotificationWrapper from './NotificationWrapper';

export default function NotificationClawbackTransaction(props: any) {
const { notification, onClick = () => {} } = props;

const { data: height, isLoading: isGetHeightInfoLoading } = useGetHeightInfoQuery(undefined, {
pollingInterval: 3000,
});

const { data: lastBlockTimeStampData, isLoading: isGetTimestampForHeightLoading } = useGetTimestampForHeightQuery({
height: height || 0,
});

const { data: autoClaimData, isLoading: isGetAutoClaimLoading } = useGetAutoClaimQuery();
const isAutoClaimEnabled = !isGetAutoClaimLoading && autoClaimData?.enabled;

const lastBlockTimeStamp = lastBlockTimeStampData?.timestamp || 0;

const t = useTrans();

const navigate = useNavigate();

function handleClick() {
navigate('/dashboard/wallets');
onClick();
}

function renderMessage() {
if (notification.passedTimeLock) {
return <Trans>Claw back transaction can be claimed</Trans>;
}
if (notification.claimed) {
return <Trans>Transaction claimed</Trans>;
}
return <Trans>You have a new claw back transaction</Trans>;
}

return (
<NotificationWrapper onClick={handleClick} icon={<AccessTimeIcon sx={{ fontSize: '32px !important' }} />}>
<Flex flexDirection="column">
<Typography variant="subtitle2" color="textSecondary">
{renderMessage()}
{' · '}
(<HumanTimestamp value={notification.timestamp} fromNow /> ago)
<Flex>
{useGetTextFromTransaction(
notification,
t,
lastBlockTimeStamp,
isAutoClaimEnabled,
isGetHeightInfoLoading,
isGetTimestampForHeightLoading
)}
</Flex>
</Typography>
<Typography variant="body2">
<MojoToChia value={notification.amount} />
</Typography>
</Flex>
</NotificationWrapper>
);
}
132 changes: 132 additions & 0 deletions packages/gui/src/components/notification/NotificationHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {
Flex,
LayoutDashboardSub,
TableControlled,
Row,
MojoToChia,
useGetTextFromTransaction,
} from '@chia-network/core';
import { t, Trans } from '@lingui/macro';
import { Typography, Box } from '@mui/material';
import moment from 'moment';
import React, { useMemo } from 'react';

import NotificationType from '../../constants/NotificationType';
import useValidNotifications from '../../hooks/useValidNotifications';
import OfferDetails from '../offers2/OfferDetails';

function renderOfferText(notification: any, type: string) {
const offerURLOrData =
'offerURL' in notification
? notification.offerURL
: 'offerData' in notification
? notification.offerData
: undefined;

if (type === 'asset') {
return <OfferDetails id={offerURLOrData} forcePlainText />;
}
return <OfferDetails id={offerURLOrData} forcePlainText requested />;
}

const getCols = (getNotificationText: any) => [
{
field: (row: Row) => (
<Box
component="span"
sx={{
position: 'relative',
top: '2px',
marginRight: '2px',
}}
>
{row.type === NotificationType.INCOMING_CLAWBACK_RECEIVE ? <Trans>Claw Back</Trans> : <Trans>Offer</Trans>}
</Box>
),
title: t`Type`,
},
{
field: (row: Row) => (
<Box
component="span"
sx={{
position: 'relative',
top: '2px',
marginRight: '2px',
}}
>
{row.type === NotificationType.INCOMING_CLAWBACK_RECEIVE ? (
<MojoToChia value={row.amount} />
) : (
renderOfferText(row, 'asset')
)}
</Box>
),
title: t`Asset`,
},
{
field: (row: Row) => (
<Box
component="span"
sx={{
position: 'relative',
top: '2px',
marginRight: '2px',
}}
>
{row.type === NotificationType.INCOMING_CLAWBACK_RECEIVE
? getNotificationText(row)
: renderOfferText(row, 'requested')}
</Box>
),
title: t`Status`,
},
{
field: (row: Row) => (
<Box
component="span"
sx={{
position: 'relative',
top: '2px',
marginRight: '2px',
}}
>
{moment(row.timestamp * 1000).format('LLL')}
</Box>
),
title: t`Creation Date`,
},
];

export default function NotificationHistory() {
const { notifications = [] } = useValidNotifications();

const [page, setPage] = React.useState(0);

function onPageChange(_: any, pageLocal: number) {
setPage(pageLocal);
}

const limited = notifications.slice(page * 10, page * 10 + 10);

const cols = useMemo(() => getCols(useGetTextFromTransaction), []);

return (
<LayoutDashboardSub>
<Flex flexDirection="column" gap={1}>
<Typography variant="h5">
<Trans>Notification history</Trans>
</Typography>
<TableControlled
cols={cols}
rows={limited ?? []}
page={page}
count={notifications.length}
uniqueField="name"
pages={!!notifications.length}
onPageChange={onPageChange}
/>
</Flex>
</LayoutDashboardSub>
);
}
10 changes: 10 additions & 0 deletions packages/gui/src/components/notification/NotificationOffer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import NotificationWrapper from './NotificationWrapper';
export type NotificationOfferProps = {
notification: NotificationCounterOffer | NotificationOfferType;
onClick?: () => void;
renderType?: string;
};

export default function NotificationOffer(props: NotificationOfferProps) {
const {
onClick,
notification,
notification: { type, timestamp },
renderType,
} = props;

const offerURLOrData =
Expand Down Expand Up @@ -74,6 +76,14 @@ export default function NotificationOffer(props: NotificationOfferProps) {
return null;
}

if (renderType === 'asset') {
return <OfferDetails id={offerURLOrData} />;
}

if (renderType === 'requested') {
return <OfferDetails id={offerURLOrData} color="primary" requested />;
}

return (
<NotificationWrapper
onClick={handleClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function NotificationWrapper(props: NotificationWrapperProps) {

return (
<MenuItem onClick={onClick} disabled={isLoading}>
<Flex alignItems="flex-start" gap={2} whiteSpace="normal">
<Flex alignItems="flex-start" gap={1} whiteSpace="normal">
<Box width={40}>{icon}</Box>
{error ? (
<Typography color="error">{error.message}</Typography>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function NotificationsMenu(props: NotificationsMenuProps) {

function handleSeeAllActivity() {
onClose?.();
navigate('/dashboard/offers');
navigate('/dashboard/history');
}

function handleClick() {
Expand Down
Loading

0 comments on commit 70cbeae

Please sign in to comment.