Skip to content

Commit

Permalink
feat(vault): staking
Browse files Browse the repository at this point in the history
  • Loading branch information
vihangpatil committed Oct 16, 2024
1 parent dee5903 commit 61c2207
Show file tree
Hide file tree
Showing 24 changed files with 939 additions and 31 deletions.
3 changes: 3 additions & 0 deletions apps/vault/src/assets/chevron-right-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/vault/src/assets/home-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions apps/vault/src/assets/vault-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions apps/vault/src/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import HomeIcon from '../assets/home-icon.svg';
import ChevronRightIcon from '../assets/chevron-right-icon.svg';
import Image from 'next/image';
import Link from 'next/link';

interface BreadcrumbsProps {
pages: Page[];
}

interface Page {
name: string;
href: string;
current?: boolean;
}

const Breadcrumbs: React.FC<BreadcrumbsProps> = ({ pages }) => {
return (
<nav aria-label="Breadcrumb" className="px-4 mt-4 flex">
<ol role="list" className="flex items-center space-x-4">
<li>
<div>
<a href="/" className="text-gray-400 hover:text-gray-500">
<Image
className={'ps-2 w-8 inline'}
src={HomeIcon}
alt={'Home'}
/>
<span className="sr-only">Home</span>
</a>
</div>
</li>
{pages.map((page) => (
<li key={page.name}>
<div className="flex items-center">
<Image
className={'ps-2 h-5 w-5 inline'}
src={ChevronRightIcon}
alt={'>'}
/>
<Link
href={page.href}
aria-current={page.current ? 'page' : undefined}
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700"
>
{page.name}
</Link>
</div>
</li>
))}
</ol>
</nav>
);
};

export default Breadcrumbs;
40 changes: 40 additions & 0 deletions apps/vault/src/components/CopyText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Image from 'next/image';
import CopyIcon from '../assets/copy-icon.png';
import React, { useState } from 'react';
import { InfoAlert } from '@/components';

interface CopyTextProps {
text: string;
alertMessage?: string;
}

const CopyText: React.FC<CopyTextProps> = ({ text, alertMessage }) => {
const [alertText, setAlertText] = useState<string | null>(null);
return (
<>
<InfoAlert
show={alertText != null}
hide={() => setAlertText(null)}
alertText={alertText || ''}
className={'my-3'}
/>
<div className={'flex flex-row no-wrap'}>
<div className={'grow-0 outline rounded p-1'}>
<span className={'font-mono'}>{text}</span>
<Image
className={'ps-2 w-8 inline'}
src={CopyIcon}
alt={'Copy'}
onClick={() =>
navigator.clipboard
.writeText(text || '')
.then(() => setAlertText(alertMessage ?? 'Copied'))
}
/>
</div>
</div>
</>
);
};

export default CopyText;
43 changes: 43 additions & 0 deletions apps/vault/src/components/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { useRouter } from 'next/router';

const tabs = [
{ name: 'Home', href: '/' },
{ name: 'Staking', href: '/staking' },
{ name: 'Staking positions', href: '/staking/positions' },
];

function classNames(...classes: string[]) {
return classes.filter(Boolean).join(' ');
}

const NavigationBar: React.FC = () => {
const router = useRouter();
const currentTab = tabs.find((tab) => tab.href === router.pathname);
const tabName = currentTab ? currentTab.name : undefined;
return (
<div>
<div className="border-b border-gray-200">
<nav aria-label="Tabs" className="-mb-px flex space-x-8">
{tabs.map((tab) => (
<a
key={tab.name}
href={tab.href}
aria-current={tab.name == tabName ? 'page' : undefined}
className={classNames(
tab.name == tabName
? 'text-brand-light-primary border-b-2 border-brand-light-primary'
: 'text-label-dark-primary',
'whitespace-nowrap h-10 p-2 text-sm font-medium'
)}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
);
};

export default NavigationBar;
8 changes: 1 addition & 7 deletions apps/vault/src/components/VaultHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import config from '@/firebase/config';
import { Header } from 'ui';
import vaultLogo from '../assets/vault-logo.svg';
import Link from 'next/link';
import { useRouter } from 'next/router';

interface VaultHeaderProps {}

// TODO: upgrade the secondary header here with the ui one
const AuthHeader = dynamic(
Expand All @@ -26,10 +23,7 @@ const AuthHeader = dynamic(
}
);

const VaultHeader: React.FC<VaultHeaderProps> = ({}) => {
const router = useRouter();
const isLanding =
router.pathname.startsWith('/products/') || router.pathname === '/';
const VaultHeader: React.FC = () => {
return (
<>
<AuthHeader
Expand Down
6 changes: 6 additions & 0 deletions apps/vault/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { default as VaultHeader } from './VaultHeader';
export { default as VaultFooter } from './VaultFooter';
export { default as NavigationBar } from './NavigationBar';
export { default as Breadcrumbs } from './Breadcrumbs';
export { default as CopyText } from './CopyText';
export { default as VaultStakingPositionStatusLabel } from './staking/VaultStakingPositionStatusLabel';
export { default as StakingAssetsTable } from './staking/VaultStakingAssetsTable';
export { default as VaultStakingPositionsTable } from './staking/positions/VaultStakingPositionsTable';
export { default as BalanceCard } from './vaultAssets/BalanceCard';
export { default as DonutChart } from './vaultAssets/DonutChart';
export { default as CurrencyDropdown } from './vaultAssets/CurrencyDropdown';
Expand Down
118 changes: 118 additions & 0 deletions apps/vault/src/components/staking/VaultStakingAssetsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as React from 'react';
import { VaultStakingAsset } from '@/types';

interface StakingVaultAssetsTableProps {
vaultStakingAssets: VaultStakingAsset[];
}

const VaultStakingAssetsTable: React.FC<StakingVaultAssetsTableProps> = ({
vaultStakingAssets,
}) => {
return (
<div
className={
'border-collapse grid grid-cols-auto sm:grid-cols-[auto_auto] md:grid-cols-[repeat(4,auto)]'
}
>
<div
className={
'bg-bg-dark-tertiary text-label-dark-secondary hidden md:grid grid-cols-subgrid col-span-4 p-3'
}
>
<div className={'ps-2 text-center text-nowrap'}>Cryptocurrency</div>
<div className={'text-center text-nowrap'}>Available</div>
<div className={'text-center text-nowrap'}>Pending</div>
<div className={'text-center text-nowrap'}>Staked</div>
</div>
{vaultStakingAssets.map(({ id, available, pending, staked }, index) => (
<div
key={id}
className={`${index % 2 ? 'bg-bg-light-primary' : 'bg-bg-light-secondary'} grid grid-cols-subgrid col-span-2 md:col-span-4 p-2`}
>
<div className={'text-center col-span-2 md:col-span-1 font-medium'}>
{id}
</div>

{available ? (
<div
className={'py-3 md:py-0 col-span-2 text-center md:col-span-1'}
>
<span className={'md:hidden text-label-light-secondary'}>
Available:
</span>
<span>{available}</span>
<br />
<span className="pt-2 isolate inline-flex rounded-md shadow-sm">
<button
type="button"
className="relative inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300"
>
Stake
</button>
</span>
</div>
) : (
<div className={'col-span-2 md:col-span-1'} />
)}
{pending ? (
<div
className={'py-3 md:py-0 col-span-2 text-center md:col-span-1'}
>
<span className={'md:hidden text-label-light-secondary'}>
Pending:
</span>
<span>{pending}</span>
<br />
<span className="pt-2 isolate inline-flex rounded-md shadow-sm">
<button
type="button"
className="relative inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300"
>
Status
</button>
</span>
</div>
) : (
<div className={'col-span-2 md:col-span-1'} />
)}

{staked ? (
<div
className={'py-3 md:py-0 col-span-2 text-center md:col-span-1'}
>
<span className={'md:hidden text-label-light-secondary'}>
Staked:
</span>
<span>{staked}</span>
<br />
<span className="pt-2 isolate inline-flex rounded-md shadow-sm">
<button
type="button"
className="relative inline-flex items-center rounded-l-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300"
>
Status
</button>
<button
type="button"
className="relative -ml-px inline-flex items-center bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300"
>
Unstake
</button>
<button
type="button"
className="relative -ml-px inline-flex items-center rounded-r-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300"
>
Claim Rewards
</button>
</span>
</div>
) : (
<div className={'col-span-2 md:col-span-1'} />
)}
</div>
))}
</div>
);
};

export default VaultStakingAssetsTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { VaultStakingPositionStatus } from '@/types';
import React from 'react';

interface VaultStakingPositionStatusLabelProps {
status: VaultStakingPositionStatus;
}

const VaultStakingPositionStatusLabel: React.FC<
VaultStakingPositionStatusLabelProps
> = ({ status }) => {
let statusColor = 'gray';
switch (status) {
case 'error':
case 'failed':
statusColor = 'red';
break;
case 'creating':
case 'activating':
case 'pending':
case 'deactivating':
case 'withdrawing':
statusColor = 'orange';
break;
case 'active':
case 'withdrawn':
statusColor = 'green';
break;
case 'canceled':
case 'deactivated':
statusColor = 'gray';
break;
}
return (
<code
className="rounded bg-bg-dark-tertiary p-1 font-mono"
style={{ backgroundColor: statusColor }}
>
{status}
</code>
);
};

export default VaultStakingPositionStatusLabel;
Loading

0 comments on commit 61c2207

Please sign in to comment.