mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
184 lines
7.2 KiB
TypeScript
184 lines
7.2 KiB
TypeScript
'use client';
|
|
|
|
import { ActionModuleTooltip } from '@/components/ActionModule';
|
|
import { NodeOperatorIndicator } from '@/components/StakedNodeCard';
|
|
import type { ReservedContributorStruct } from '@/hooks/useCreateOpenNodeRegistration';
|
|
import { useCurrentActor } from '@/hooks/useCurrentActor';
|
|
import { SESSION_NODE_FULL_STAKE_AMOUNT } from '@/lib/constants';
|
|
import { formatPercentage } from '@/lib/locale-client';
|
|
import { ButtonDataTestId } from '@/testing/data-test-ids';
|
|
import { TOKEN } from '@session/contracts';
|
|
import { formatSENTBigIntNoRounding } from '@session/contracts/hooks/Token';
|
|
import { EditButton } from '@session/ui/components/EditButton';
|
|
import { PubKey } from '@session/ui/components/PubKey';
|
|
import { RemoveButton } from '@session/ui/components/RemoveButton';
|
|
import { cn } from '@session/ui/lib/utils';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableFooter,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@session/ui/ui/table';
|
|
import { bigIntToNumber } from '@session/util-crypto/maths';
|
|
import { areHexesEqual } from '@session/util-crypto/string';
|
|
import { PubkeyWithEns } from '@session/wallet/components/PubkeyWithEns';
|
|
import { useTranslations } from 'next-intl';
|
|
import { type ReactNode, useMemo } from 'react';
|
|
|
|
type ReservedStakeRow = ReservedContributorStruct & { percentage: number };
|
|
|
|
export function ReservedStakesTable({
|
|
actionButton,
|
|
children,
|
|
className,
|
|
editRowOnClick,
|
|
isEditable,
|
|
removeRowOnClick,
|
|
reservedStakes,
|
|
}: {
|
|
actionButton?: ReactNode;
|
|
children?: ReactNode;
|
|
className?: string;
|
|
editRowOnClick?: (i: number) => void;
|
|
isEditable?: boolean;
|
|
removeRowOnClick?: (i: number) => void;
|
|
reservedStakes: Array<ReservedContributorStruct>;
|
|
}) {
|
|
const dict = useTranslations('actionModules.registration.reserveSlotsInput');
|
|
const dictGeneral = useTranslations('general');
|
|
const address = useCurrentActor();
|
|
|
|
const [slotRows, unreservedStake] = useMemo(() => {
|
|
const rows: Array<ReservedStakeRow> = [];
|
|
let remaining = SESSION_NODE_FULL_STAKE_AMOUNT;
|
|
|
|
for (const { amount, addr } of reservedStakes) {
|
|
remaining -= amount;
|
|
rows.push({
|
|
addr,
|
|
amount,
|
|
percentage:
|
|
bigIntToNumber(amount, TOKEN.DECIMALS) /
|
|
bigIntToNumber(SESSION_NODE_FULL_STAKE_AMOUNT, TOKEN.DECIMALS),
|
|
});
|
|
}
|
|
|
|
return [rows, remaining];
|
|
}, [reservedStakes]);
|
|
|
|
const remainingStake = formatSENTBigIntNoRounding(unreservedStake);
|
|
const remainingStakePercent = formatPercentage(
|
|
bigIntToNumber(unreservedStake, TOKEN.DECIMALS) /
|
|
bigIntToNumber(SESSION_NODE_FULL_STAKE_AMOUNT, TOKEN.DECIMALS),
|
|
{ minimumFractionDigits: 0 }
|
|
);
|
|
|
|
return (
|
|
<div className={cn('relative', className)}>
|
|
<div className="relative overflow-hidden rounded-xl border border-session-text">
|
|
<Table size="compact">
|
|
<TableHeader>
|
|
<TableRow className="border-b-transparent bg-transparent hover:bg-transparent">
|
|
<TableHead />
|
|
<TableHead className="ps-0">{dict('address')}</TableHead>
|
|
<TableHead className="text-end">{dict('stakeAmount')}</TableHead>
|
|
<TableHead
|
|
className={isEditable && slotRows.length > 1 ? '' : 'text-end'}
|
|
colSpan={isEditable ? 2 : 1}
|
|
>
|
|
{dict('percentage')}
|
|
</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{slotRows.map(({ addr, amount, percentage }, i) => (
|
|
<TableRow key={addr}>
|
|
<TableCell>
|
|
<div className="-me-3 ms-auto w-max">
|
|
{i === 0 ? (
|
|
<NodeOperatorIndicator isConnectedWallet={areHexesEqual(address, addr)} />
|
|
) : null}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex flex-row items-center justify-start gap-2 ps-0 align-middle">
|
|
{i !== 0 && areHexesEqual(address, addr) ? (
|
|
<>
|
|
<span className="font-bold">({dictGeneral('you')})</span>
|
|
<PubKey pubKey={addr} force="collapse" alwaysShowCopyButton />
|
|
</>
|
|
) : (
|
|
<PubkeyWithEns pubKey={addr} force="collapse" alwaysShowCopyButton />
|
|
)}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-end">{formatSENTBigIntNoRounding(amount)}</TableCell>
|
|
<TableCell className="text-end">
|
|
{formatPercentage(percentage, { minimumFractionDigits: 0 })}
|
|
</TableCell>
|
|
{isEditable ? (
|
|
<TableCell>
|
|
{/* Only the last slot can be edited TODO: investigate if we can do out of order mutations. */}
|
|
{i !== 0 && i === reservedStakes.length - 1 ? (
|
|
<div className="flex flex-row justify-center gap-1">
|
|
{editRowOnClick ? (
|
|
<EditButton
|
|
data-testid={ButtonDataTestId.Reserved_Stakes_Table_Edit_Row}
|
|
onClick={() => editRowOnClick(i)}
|
|
/>
|
|
) : null}
|
|
{removeRowOnClick ? (
|
|
<RemoveButton
|
|
data-testid={ButtonDataTestId.Reserved_Stakes_Table_Edit_Row}
|
|
onClick={() => removeRowOnClick(i)}
|
|
/>
|
|
) : null}
|
|
</div>
|
|
) : null}
|
|
</TableCell>
|
|
) : null}
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
<TableFooter>
|
|
<TableRow className="[&>td]:py-3">
|
|
<TableCell colSpan={1} className="px-2.5" />
|
|
<TableCell colSpan={unreservedStake ? 1 : 3} className="px-2.5">
|
|
<div className="flex flex-row items-center gap-2">
|
|
{dict(unreservedStake ? 'remainingStake' : 'remainingStakeNone')}
|
|
{unreservedStake ? (
|
|
<ActionModuleTooltip>
|
|
{dict(
|
|
isEditable
|
|
? 'remainingStakeCreationDescription'
|
|
: 'remainingStakeViewDescription',
|
|
{ amount: remainingStake }
|
|
)}
|
|
</ActionModuleTooltip>
|
|
) : null}
|
|
</div>
|
|
</TableCell>
|
|
{unreservedStake ? (
|
|
<TableCell className="px-2.5 text-end">{remainingStake}</TableCell>
|
|
) : null}
|
|
{unreservedStake ? (
|
|
<TableCell className="px-2.5 text-end">{remainingStakePercent}</TableCell>
|
|
) : null}
|
|
{isEditable ? <TableCell /> : null}
|
|
</TableRow>
|
|
<TableRow className="hover:bg-session-black">
|
|
<TableCell colSpan={isEditable ? 5 : 4} className="px-2.5">
|
|
{children}
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableFooter>
|
|
</Table>
|
|
</div>
|
|
{actionButton ? <div className="-bottom-3 -right-3 absolute">{actionButton}</div> : null}
|
|
</div>
|
|
);
|
|
}
|