Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallet-dashboard): polish homepage scroll #4502

Merged
merged 43 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
aeb1e12
feat: add supply increase vesting overview to homepage
cpl121 Dec 10, 2024
f000422
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 10, 2024
719e94c
fix: linter
cpl121 Dec 10, 2024
6ed7173
fix(dashboard): remove isHoverable prop
cpl121 Dec 12, 2024
c8a80e5
fix(dashboard): use showDays in formatCountdown
cpl121 Dec 12, 2024
2499a57
fix(dashboard): rename vesting by supplyIncreaseVesting
cpl121 Dec 12, 2024
d462085
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 12, 2024
4c9131b
fix: format
cpl121 Dec 12, 2024
49f7d0d
fix(dashboard): build
cpl121 Dec 12, 2024
e242925
fix(dashboard): format
cpl121 Dec 12, 2024
4329b2c
Merge branch 'develop' into tooling-dashboard/feat-add-supply-increas…
evavirseda Dec 13, 2024
a30e75b
fix(dashboard): styles
cpl121 Dec 13, 2024
5c3b9b3
fix(dashboard): isTimelockedStakedObjectsLoading name and join 2 inva…
cpl121 Dec 13, 2024
d7d2f1c
feat: polish homepage scroll
evavirseda Dec 16, 2024
61e24fd
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 16, 2024
bfd9bf8
fix(dashboard): format
cpl121 Dec 16, 2024
6f389ed
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 16, 2024
59efdc7
feat: update styles and add missing dependency
evavirseda Dec 16, 2024
9848b71
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 16, 2024
cf67de8
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 17, 2024
d477224
feat: add min height
evavirseda Dec 17, 2024
9bc8af9
feat. add padding
evavirseda Dec 17, 2024
22fac05
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 17, 2024
7abc237
fix(dasboard): undo the split of the query invalidation
cpl121 Dec 17, 2024
9c0ab6e
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 17, 2024
2eb5095
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 17, 2024
dd7569b
fix(dashboard): rename unlockAllsupplyIncreaseVesting and disable new…
cpl121 Dec 17, 2024
96b4dd3
Merge branch 'develop' into tooling-dashboard/feat-add-supply-increas…
evavirseda Dec 17, 2024
b46a664
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 17, 2024
6ada5aa
fix grid
evavirseda Dec 17, 2024
8332343
Merge branches 'tooling-dashboard/feat-add-supply-increase-vesting-ov…
cpl121 Dec 17, 2024
2024575
feat(dashboard): add object for the options in useCountdownByTimestamp
cpl121 Dec 17, 2024
4b268f8
fix: linter
cpl121 Dec 17, 2024
184923e
fix: linter
cpl121 Dec 17, 2024
71ca4ef
fix(core): improve naming
cpl121 Dec 18, 2024
20a1cc4
fix(core): linter
cpl121 Dec 18, 2024
c30635b
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 18, 2024
05b6da6
Merge branch 'develop' into tooling-dashboard/feat-add-supply-increas…
brancoder Dec 18, 2024
e48eec4
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 18, 2024
eb9facb
Merge branch 'develop' into tooling-dashboard/feat-add-supply-increas…
cpl121 Dec 18, 2024
40b68e7
Merge branch 'develop' into tooling-dashboard/feat-add-supply-increas…
brancoder Dec 18, 2024
e7aded9
Merge branch 'tooling-dashboard/feat-add-supply-increase-vesting-over…
evavirseda Dec 18, 2024
12eb0dd
Merge branch 'develop' into tooling-dashboard/polish-homepage-scroll
evavirseda Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions apps/core/src/hooks/useCountdownByTimestamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
MILLISECONDS_PER_SECOND,
} from '../constants';

export function useCountdownByTimestamp(initialTimestamp: number | null): string {
export function useCountdownByTimestamp(
initialTimestamp: number | null,
showSeconds = true,
showMinutes = true,
showHours = true,
showDays = true,
): string {
const [timeRemainingMs, setTimeRemainingMs] = useState<number>(0);

useEffect(() => {
Expand All @@ -22,11 +28,23 @@ export function useCountdownByTimestamp(initialTimestamp: number | null): string

return () => clearInterval(interval);
}, [initialTimestamp]);
const formattedCountdown = formatCountdown(timeRemainingMs);
const formattedCountdown = formatCountdown(
timeRemainingMs,
showSeconds,
showMinutes,
showHours,
showDays,
);
return formattedCountdown;
}

function formatCountdown(totalMilliseconds: number) {
function formatCountdown(
totalMilliseconds: number,
showSeconds: boolean,
showMinutes: boolean,
showHours: boolean,
showDays: boolean,
) {
const days = Math.floor(totalMilliseconds / MILLISECONDS_PER_DAY);
const hours = Math.floor((totalMilliseconds % MILLISECONDS_PER_DAY) / MILLISECONDS_PER_HOUR);
const minutes = Math.floor(
Expand All @@ -36,11 +54,11 @@ function formatCountdown(totalMilliseconds: number) {
(totalMilliseconds % MILLISECONDS_PER_MINUTE) / MILLISECONDS_PER_SECOND,
);

const timeUnits = [];
if (days > 0) timeUnits.push(`${days}d`);
if (hours > 0) timeUnits.push(`${hours}h`);
if (minutes > 0) timeUnits.push(`${minutes}m`);
if (seconds > 0 || timeUnits.length === 0) timeUnits.push(`${seconds}s`);
const timeUnits: string[] = [];
if (showDays && days > 0) timeUnits.push(`${days}d`);
if (showHours && hours > 0) timeUnits.push(`${hours}h`);
if (showMinutes && minutes > 0) timeUnits.push(`${minutes}m`);
if (showSeconds && (seconds > 0 || timeUnits.length === 0)) timeUnits.push(`${seconds}s`);

return timeUnits.join(' ');
}
10 changes: 5 additions & 5 deletions apps/wallet-dashboard/app/(protected)/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
TransactionsOverview,
StakingOverview,
MigrationOverview,
SupplyIncreaseVestingOverview,
} from '@/components';
import { useFeature } from '@growthbook/growthbook-react';
import { Feature } from '@iota/core';
Expand All @@ -18,25 +19,24 @@ function HomeDashboardPage(): JSX.Element {
const account = useCurrentAccount();

const stardustMigrationEnabled = useFeature<boolean>(Feature.StardustMigration).value;
const supplyIncreaseVestingEnabled = useFeature<boolean>(Feature.SupplyIncreaseVesting).value;

return (
<main className="flex flex-1 flex-col items-center space-y-8 py-md">
{connectionStatus === 'connected' && account && (
<>
<div className="home-page-grid-container h-full w-full">
<div className="home-page-grid-container w-full">
evavirseda marked this conversation as resolved.
Show resolved Hide resolved
<div style={{ gridArea: 'balance' }} className="flex grow overflow-hidden">
<AccountBalance />
</div>
<div style={{ gridArea: 'staking' }} className="flex grow overflow-hidden">
<StakingOverview />
</div>
{stardustMigrationEnabled && <MigrationOverview />}
<div style={{ gridArea: 'coins' }}>
<div style={{ gridArea: 'coins' }} className="flex grow overflow-hidden">
<MyCoins />
</div>
<div style={{ gridArea: 'vesting' }} className="flex grow overflow-hidden">
Vesting
</div>
{supplyIncreaseVestingEnabled && <SupplyIncreaseVestingOverview />}
<div style={{ gridArea: 'activity' }} className="flex grow overflow-hidden">
<TransactionsOverview />
</div>
Expand Down
116 changes: 37 additions & 79 deletions apps/wallet-dashboard/app/(protected)/vesting/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,8 @@ import {
useStakeDialog,
VestingScheduleDialog,
} from '@/components';
import { useGetCurrentEpochStartTimestamp, useNotifications, usePopups } from '@/hooks';
import {
buildSupplyIncreaseVestingSchedule,
formatDelegatedTimelockedStake,
getLatestOrEarliestSupplyIncreaseVestingPayout,
getVestingOverview,
groupTimelockedStakedObjects,
isTimelockedUnlockable,
mapTimelockObjects,
TimelockedStakedObjectsGrouped,
} from '@/lib/utils';
import { useGetSupplyIncreaseVestingObjects, useNotifications, usePopups } from '@/hooks';
import { groupTimelockedStakedObjects, TimelockedStakedObjectsGrouped } from '@/lib/utils';
import { NotificationType } from '@/stores/notificationStore';
import { useFeature } from '@growthbook/growthbook-react';
import {
Expand All @@ -47,10 +38,7 @@ import {
TIMELOCK_IOTA_TYPE,
useFormatCoin,
useGetActiveValidatorsInfo,
useGetAllOwnedObjects,
useGetTimelockedStakedObjects,
useTheme,
useUnlockTimelockedObjectsTransaction,
useCountdownByTimestamp,
Feature,
} from '@iota/core';
Expand All @@ -70,22 +58,15 @@ import { StakedTimelockObject } from '@/components';

function VestingDashboardPage(): JSX.Element {
const account = useCurrentAccount();
const address = account?.address || '';
const queryClient = useQueryClient();
const iotaClient = useIotaClient();
const router = useRouter();
const { data: system } = useIotaClientQuery('getLatestIotaSystemState');
const [isVestingScheduleDialogOpen, setIsVestingScheduleDialogOpen] = useState(false);
const { addNotification } = useNotifications();
const { openPopup, closePopup } = usePopups();
const { data: currentEpochMs } = useGetCurrentEpochStartTimestamp();
const { data: activeValidators } = useGetActiveValidatorsInfo();
const { data: timelockedObjects } = useGetAllOwnedObjects(account?.address || '', {
StructType: TIMELOCK_IOTA_TYPE,
});

const { data: timelockedStakedObjects, isLoading: istimelockedStakedObjectsLoading } =
useGetTimelockedStakedObjects(account?.address || '');

const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction();
const { theme } = useTheme();

Expand All @@ -96,16 +77,18 @@ function VestingDashboardPage(): JSX.Element {

const supplyIncreaseVestingEnabled = useFeature<boolean>(Feature.SupplyIncreaseVesting).value;

const timelockedMapped = mapTimelockObjects(timelockedObjects || []);
const timelockedstakedMapped = formatDelegatedTimelockedStake(timelockedStakedObjects || []);
const {
nextPayout,
supplyIncreaseVestingPortfolio,
supplyIncreaseVestingSchedule,
supplyIncreaseVestingMapped,
supplyIncreaseVestingStakedMapped,
isTimelockedStakedObjectsLoading,
unlockAllsupplyIncreaseVesting,
} = useGetSupplyIncreaseVestingObjects(address);

const timelockedStakedObjectsGrouped: TimelockedStakedObjectsGrouped[] =
groupTimelockedStakedObjects(timelockedstakedMapped || []);

const vestingSchedule = getVestingOverview(
[...timelockedMapped, ...timelockedstakedMapped],
Number(currentEpochMs),
);
groupTimelockedStakedObjects(supplyIncreaseVestingStakedMapped || []);

const {
isDialogStakeOpen,
Expand All @@ -118,37 +101,32 @@ function VestingDashboardPage(): JSX.Element {
handleNewStake,
} = useStakeDialog();

const nextPayout = getLatestOrEarliestSupplyIncreaseVestingPayout(
[...timelockedMapped, ...timelockedstakedMapped],
Number(currentEpochMs),
false,
);

const lastPayout = getLatestOrEarliestSupplyIncreaseVestingPayout(
[...timelockedMapped, ...timelockedstakedMapped],
Number(currentEpochMs),
true,
);

const vestingPortfolio =
lastPayout && buildSupplyIncreaseVestingSchedule(lastPayout, Number(currentEpochMs));

const formattedLastPayoutExpirationTime = useCountdownByTimestamp(
Number(nextPayout?.expirationTimestampMs),
);

const [formattedTotalVested, vestedSymbol] = useFormatCoin(
vestingSchedule.totalVested,
supplyIncreaseVestingSchedule.totalVested,
IOTA_TYPE_ARG,
);

const [formattedTotalLocked, lockedSymbol] = useFormatCoin(
vestingSchedule.totalLocked,
supplyIncreaseVestingSchedule.totalLocked,
IOTA_TYPE_ARG,
);

const [formattedAvailableClaiming, availableClaimingSymbol] = useFormatCoin(
vestingSchedule.availableClaiming,
supplyIncreaseVestingSchedule.availableClaiming,
IOTA_TYPE_ARG,
);

const [totalStakedFormatted, totalStakedSymbol] = useFormatCoin(
supplyIncreaseVestingSchedule.totalStaked,
IOTA_TYPE_ARG,
);

const [totalEarnedFormatted, totalEarnedSymbol] = useFormatCoin(
supplyIncreaseVestingSchedule.totalEarned,
IOTA_TYPE_ARG,
);

Expand All @@ -163,26 +141,6 @@ function VestingDashboardPage(): JSX.Element {
);
}

const [totalStakedFormatted, totalStakedSymbol] = useFormatCoin(
vestingSchedule.totalStaked,
IOTA_TYPE_ARG,
);

const [totalEarnedFormatted, totalEarnedSymbol] = useFormatCoin(
vestingSchedule.totalEarned,
IOTA_TYPE_ARG,
);

const unlockedTimelockedObjects = timelockedMapped?.filter((timelockedObject) =>
isTimelockedUnlockable(timelockedObject, Number(currentEpochMs)),
);
const unlockedTimelockedObjectIds: string[] =
unlockedTimelockedObjects.map((timelocked) => timelocked.id.id) || [];
const { data: unlockAllTimelockedObjects } = useUnlockTimelockedObjectsTransaction(
account?.address || '',
unlockedTimelockedObjectIds,
);

function handleOnSuccess(digest: string): void {
iotaClient
.waitForTransaction({
Expand All @@ -205,13 +163,13 @@ function VestingDashboardPage(): JSX.Element {
}

const handleCollect = () => {
if (!unlockAllTimelockedObjects?.transactionBlock) {
if (!unlockAllsupplyIncreaseVesting?.transactionBlock) {
addNotification('Failed to create a Transaction', NotificationType.Error);
return;
}
signAndExecuteTransaction(
{
transaction: unlockAllTimelockedObjects.transactionBlock,
transaction: unlockAllsupplyIncreaseVesting.transactionBlock,
},
{
onSuccess: (tx) => {
Expand Down Expand Up @@ -255,7 +213,7 @@ function VestingDashboardPage(): JSX.Element {
}
}, [router, supplyIncreaseVestingEnabled]);

if (istimelockedStakedObjectsLoading) {
if (isTimelockedStakedObjectsLoading) {
return (
<div className="flex w-full max-w-4xl items-start justify-center justify-self-center">
<LoadingIndicator />
Expand Down Expand Up @@ -297,8 +255,8 @@ function VestingDashboardPage(): JSX.Element {
title="Collect"
buttonType={ButtonType.Primary}
buttonDisabled={
!vestingSchedule.availableClaiming ||
vestingSchedule.availableClaiming === 0n
!supplyIncreaseVestingSchedule.availableClaiming ||
supplyIncreaseVestingSchedule.availableClaiming === 0n
}
/>
</Card>
Expand All @@ -319,20 +277,20 @@ function VestingDashboardPage(): JSX.Element {
onClick={openReceiveTokenPopup}
title="See All"
buttonType={ButtonType.Secondary}
buttonDisabled={!vestingPortfolio}
buttonDisabled={!supplyIncreaseVestingPortfolio}
/>
</Card>
{vestingPortfolio && (
{supplyIncreaseVestingPortfolio && (
<VestingScheduleDialog
open={isVestingScheduleDialogOpen}
setOpen={setIsVestingScheduleDialogOpen}
vestingPortfolio={vestingPortfolio}
vestingPortfolio={supplyIncreaseVestingPortfolio}
/>
)}
</div>
</Panel>

{timelockedstakedMapped.length === 0 ? (
{supplyIncreaseVestingMapped.length === 0 ? (
<Banner
videoSrc={videoSrc}
title="Stake Vested Tokens"
Expand All @@ -343,7 +301,7 @@ function VestingDashboardPage(): JSX.Element {
) : null}
</div>

{timelockedstakedMapped.length !== 0 ? (
{supplyIncreaseVestingStakedMapped.length !== 0 ? (
<div className="flex w-full md:w-1/2">
<Panel>
<Title
Expand Down Expand Up @@ -406,7 +364,7 @@ function VestingDashboardPage(): JSX.Element {
setView={setStakeDialogView}
selectedValidator={selectedValidator}
setSelectedValidator={setSelectedValidator}
maxStakableTimelockedAmount={BigInt(vestingSchedule.availableStaking)}
maxStakableTimelockedAmount={BigInt(supplyIncreaseVestingSchedule.availableStaking)}
/>
</div>
);
Expand Down
Loading
Loading