From 181a45d422438c1d9ca1c6e62f8e16935d295fcc Mon Sep 17 00:00:00 2001 From: Victor Creed Date: Tue, 19 Sep 2023 13:54:06 +0300 Subject: [PATCH 1/3] feat: vesting delegate history --- .../StakingHistoryFrame.constants.ts | 4 + .../StakingHistoryFrame.tsx | 7 + .../StakingHistoryFrame.type.ts | 1 + .../VestingDelegateChanges.constants.tsx | 45 ++ .../VestingDelegateChanges.tsx | 172 +++++ .../VestingDelegateChanges.types.ts | 11 + .../VestingDelegateChanges.utils.tsx | 17 + .../hooks/useGetStakingDelegateChanges.ts | 62 ++ .../frontend/src/locales/en/translations.json | 1 + .../src/utils/graphql/rsk/generated.tsx | 655 +++++++++++++++++- .../getVestingDelegateChanges.graphql | 31 + .../src/utils/graphql/rsk/schema.graphql | 493 ++++++++++++- 12 files changed, 1485 insertions(+), 14 deletions(-) create mode 100644 apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.constants.tsx create mode 100644 apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.tsx create mode 100644 apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.types.ts create mode 100644 apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.utils.tsx create mode 100644 apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/hooks/useGetStakingDelegateChanges.ts create mode 100644 apps/frontend/src/utils/graphql/rsk/operations/getVestingDelegateChanges.graphql diff --git a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.constants.ts b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.constants.ts index 6e2cb7136..12f410a0b 100644 --- a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.constants.ts +++ b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.constants.ts @@ -20,4 +20,8 @@ export const stakingHistoryOptions = [ value: StakingHistoryType.delegate, label: t(translations.stakingHistory.delegate), }, + { + value: StakingHistoryType.delegateVesting, + label: t(translations.stakingHistory.delegateVesting), + }, ]; diff --git a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.tsx b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.tsx index 9e60698f2..f45152f5c 100644 --- a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.tsx +++ b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.tsx @@ -5,6 +5,7 @@ import { StakingDelegateChanges } from './components/StakingDelegateChanges/Stak import { StakingExtendedDuration } from './components/StakingExtendedDuration/StakingExtendedDuration'; import { StakingHistory } from './components/StakingHistory/StakingHistory'; import { StakingWithdraws } from './components/StakingWithdraws/StakingWithdraws'; +import { VestingDelegateChanges } from './components/VestingDelegateChanges/VestingDelegateChanges'; export const StakingHistoryFrame: FC = () => { const [selectedHistoryType, setSelectedHistoryType] = useState( @@ -40,6 +41,12 @@ export const StakingHistoryFrame: FC = () => { onChangeHistoryType={onChangeHistoryType} /> )} + {selectedHistoryType === StakingHistoryType.delegateVesting && ( + + )} ); }; diff --git a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.type.ts b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.type.ts index dc513a8e4..4c8ce160b 100644 --- a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.type.ts +++ b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/StakingHistoryFrame.type.ts @@ -3,6 +3,7 @@ export enum StakingHistoryType { unstake = 'unstake', extend = 'extend', delegate = 'delegate', + delegateVesting = 'delegateVesting', } export type StakingHistoryProps = { diff --git a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.constants.tsx b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.constants.tsx new file mode 100644 index 000000000..483d665c6 --- /dev/null +++ b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.constants.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import { t } from 'i18next'; + +import { TransactionIdRenderer } from '../../../../2_molecules/TransactionIdRenderer/TransactionIdRenderer'; +import { TxIdWithNotification } from '../../../../2_molecules/TxIdWithNotification/TransactionIdWithNotification'; +import { translations } from '../../../../../locales/i18n'; +import { dateFormat, getRskExplorerUrl } from '../../../../../utils/helpers'; +import { VestingDelegateChangeItem } from './VestingDelegateChanges.types'; + +const rskExplorerUrl = getRskExplorerUrl(); + +export const COLUMNS_CONFIG = [ + { + id: 'timestamp', + title: t(translations.common.tables.columnTitles.timestamp), + cellRenderer: (tx: VestingDelegateChangeItem) => dateFormat(tx.timestamp), + sortable: true, + }, + { + id: 'transactionType', + title: t(translations.common.tables.columnTitles.transactionType), + cellRenderer: () => t(translations.stakingHistory.delegate), + }, + { + id: 'delegate', + title: t(translations.stakingHistory.newDelegate), + cellRenderer: (tx: VestingDelegateChangeItem) => ( + + ), + }, + { + id: 'txId', + title: t(translations.common.tables.columnTitles.transactionID), + cellRenderer: (item: VestingDelegateChangeItem) => ( + + ), + }, +]; diff --git a/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.tsx b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.tsx new file mode 100644 index 000000000..dca363a40 --- /dev/null +++ b/apps/frontend/src/app/3_organisms/StakingHistoryFrame/components/VestingDelegateChanges/VestingDelegateChanges.tsx @@ -0,0 +1,172 @@ +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; + +import { nanoid } from 'nanoid'; +import { useTranslation } from 'react-i18next'; + +import { + ErrorBadge, + ErrorLevel, + NotificationType, + OrderDirection, + OrderOptions, + Pagination, + Select, + Table, +} from '@sovryn/ui'; + +import { ExportCSV } from '../../../../2_molecules/ExportCSV/ExportCSV'; +import { + DEFAULT_HISTORY_FRAME_PAGE_SIZE, + EXPORT_RECORD_LIMIT, +} from '../../../../../constants/general'; +import { useNotificationContext } from '../../../../../contexts/NotificationContext'; +import { useAccount } from '../../../../../hooks/useAccount'; +import { useMaintenance } from '../../../../../hooks/useMaintenance'; +import { translations } from '../../../../../locales/i18n'; +import { rskClient } from '../../../../../utils/clients'; +import { + useGetDelegateChangesForVestingsLazyQuery, + VestingHistoryItem_OrderBy, +} from '../../../../../utils/graphql/rsk/generated'; +import { dateFormat } from '../../../../../utils/helpers'; +import { stakingHistoryOptions } from '../../StakingHistoryFrame.constants'; +import { StakingHistoryProps } from '../../StakingHistoryFrame.type'; +import { COLUMNS_CONFIG } from './VestingDelegateChanges.constants'; +import { generateRowTitle } from './VestingDelegateChanges.utils'; +import { useGetStakingDelegateChanges } from './hooks/useGetStakingDelegateChanges'; + +const pageSize = DEFAULT_HISTORY_FRAME_PAGE_SIZE; + +export const VestingDelegateChanges: FC = ({ + onChangeHistoryType, + selectedHistoryType, +}) => { + const { t } = useTranslation(); + const { account } = useAccount(); + const { addNotification } = useNotificationContext(); + + const [page, setPage] = useState(0); + + const { checkMaintenance, States } = useMaintenance(); + const exportLocked = checkMaintenance(States.ZERO_EXPORT_CSV); + + const [orderOptions, setOrderOptions] = useState({ + orderBy: 'timestamp', + orderDirection: OrderDirection.Desc, + }); + + const { data, loading, ids } = useGetStakingDelegateChanges( + account, + pageSize, + page, + orderOptions, + ); + + const [getStakes] = useGetDelegateChangesForVestingsLazyQuery({ + client: rskClient, + }); + + const onPageChange = useCallback( + (value: number) => { + if (data.length < pageSize && value > page) { + return; + } + setPage(value); + }, + [page, data.length], + ); + + const isNextButtonDisabled = useMemo( + () => !loading && data?.length < pageSize, + [loading, data], + ); + + const exportData = useCallback(async () => { + const { data } = await getStakes({ + variables: { + vestingContracts: ids, + skip: 0, + pageSize: EXPORT_RECORD_LIMIT, + orderBy: orderOptions.orderBy as VestingHistoryItem_OrderBy, + orderDirection: orderOptions.orderDirection, + }, + }); + + let list = data?.vestingHistoryItems || []; + + if (!list || !list.length) { + addNotification({ + type: NotificationType.warning, + title: t(translations.common.tables.actions.noDataToExport), + content: '', + dismissible: true, + id: nanoid(), + }); + } + + return list.map(item => ({ + timestamp: dateFormat(item.timestamp), + transactionType: t(translations.stakingHistory.delegate), + newDelegate: item.delegatee?.id, + TXID: item.transaction.id, + })); + }, [ + getStakes, + ids, + orderOptions.orderBy, + orderOptions.orderDirection, + addNotification, + t, + ]); + + useEffect(() => { + setPage(0); + }, [orderOptions]); + + return ( + <> +
+