diff --git a/apps/tangle-dapp/app/liquid-staking/page.tsx b/apps/tangle-dapp/app/liquid-staking/page.tsx
index 78e7cdc3e..19db1cf57 100644
--- a/apps/tangle-dapp/app/liquid-staking/page.tsx
+++ b/apps/tangle-dapp/app/liquid-staking/page.tsx
@@ -42,7 +42,12 @@ const LiquidStakingPage: FC = () => {
value ? SearchParamAction.STAKE : SearchParamAction.UNSTAKE,
});
- const { lsNetworkId } = useLsStore();
+ const {
+ lsNetworkId,
+ setIsStaking: setIsStakingInStore,
+ isStaking: isStakingInStore,
+ } = useLsStore();
+
const { network } = useNetworkStore();
const { switchNetwork } = useNetworkSwitcher();
@@ -57,6 +62,18 @@ const LiquidStakingPage: FC = () => {
}
}, [lsTangleNetwork, network.id, lsNetworkId, switchNetwork]);
+ // Sync the Zustand store state of whether liquid staking or unstaking with
+ // the URL param state.
+ useEffect(() => {
+ setIsStakingInStore(isStaking);
+ }, [isStaking, setIsStakingInStore]);
+
+ // Sync the URL param state of whether liquid staking or unstaking with
+ // the Zustand store state.
+ useEffect(() => {
+ setIsStaking(isStakingInStore);
+ }, [isStakingInStore, setIsStaking]);
+
return (
diff --git a/apps/tangle-dapp/components/BlueIconButton.tsx b/apps/tangle-dapp/components/BlueIconButton.tsx
new file mode 100644
index 000000000..97f0b71f7
--- /dev/null
+++ b/apps/tangle-dapp/components/BlueIconButton.tsx
@@ -0,0 +1,46 @@
+import { IconBase } from '@webb-tools/icons/types';
+import {
+ IconButton,
+ Tooltip,
+ TooltipBody,
+ TooltipTrigger,
+} from '@webb-tools/webb-ui-components';
+import { FC, JSX } from 'react';
+import { twMerge } from 'tailwind-merge';
+
+export type BlueIconButtonProps = {
+ onClick: () => unknown;
+ tooltip: string;
+ Icon: (props: IconBase) => JSX.Element;
+ isDisabled?: boolean;
+};
+
+const BlueIconButton: FC
= ({
+ onClick,
+ tooltip,
+ Icon,
+ isDisabled = false,
+}) => {
+ return (
+
+
+
+
+
+
+
+
+ {tooltip}
+
+
+ );
+};
+
+export default BlueIconButton;
diff --git a/apps/tangle-dapp/containers/LsMyPoolsTable.tsx b/apps/tangle-dapp/containers/LsMyPoolsTable.tsx
index 114547aae..99d84a891 100644
--- a/apps/tangle-dapp/containers/LsMyPoolsTable.tsx
+++ b/apps/tangle-dapp/containers/LsMyPoolsTable.tsx
@@ -11,19 +11,22 @@ import {
} from '@tanstack/react-table';
import { Table } from '../../../libs/webb-ui-components/src/components/Table';
import { Pagination } from '../../../libs/webb-ui-components/src/components/Pagination';
-import { LsPool } from '../constants/liquidStaking/types';
+import { LsPool, LsProtocolId } from '../constants/liquidStaking/types';
import {
ActionsDropdown,
Avatar,
AvatarGroup,
Button,
- IconButton,
TANGLE_DOCS_URL,
Typography,
} from '@webb-tools/webb-ui-components';
import TokenAmountCell from '../components/tableCells/TokenAmountCell';
import pluralize from '../utils/pluralize';
-import { ArrowRight } from '@webb-tools/icons';
+import {
+ ArrowRight,
+ SubtractCircleLineIcon,
+ TokenIcon,
+} from '@webb-tools/icons';
import useLsPools from '../data/liquidStaking/useLsPools';
import useSubstrateAddress from '../hooks/useSubstrateAddress';
import { BN } from '@polkadot/util';
@@ -32,11 +35,14 @@ import { GlassCard, TableStatus } from '../components';
import PercentageCell from '../components/tableCells/PercentageCell';
import { EMPTY_VALUE_PLACEHOLDER } from '../constants';
import { ActionItemType } from '@webb-tools/webb-ui-components/components/ActionsDropdown/types';
-import { MinusCircledIcon } from '@radix-ui/react-icons';
import { useLsStore } from '../data/liquidStaking/useLsStore';
+import BlueIconButton from '../components/BlueIconButton';
+import getLsProtocolDef from '../utils/liquidStaking/getLsProtocolDef';
+import useIsAccountConnected from '../hooks/useIsAccountConnected';
type MyLsPoolRow = LsPool & {
myStake: BN;
+ lsProtocolId: LsProtocolId;
isRoot: boolean;
isNominator: boolean;
isBouncer: boolean;
@@ -45,8 +51,10 @@ type MyLsPoolRow = LsPool & {
const COLUMN_HELPER = createColumnHelper();
const LsMyPoolsTable: FC = () => {
+ const isAccountConnected = useIsAccountConnected();
const substrateAddress = useSubstrateAddress();
const [sorting, setSorting] = useState([]);
+ const { setIsStaking, setLsPoolId, lsPoolId, isStaking } = useLsStore();
const [{ pageIndex, pageSize }, setPagination] = useState({
pageIndex: 0,
@@ -84,11 +92,16 @@ const LsMyPoolsTable: FC = () => {
isRoot: lsPool.ownerAddress === substrateAddress,
isNominator: lsPool.nominatorAddress === substrateAddress,
isBouncer: lsPool.bouncerAddress === substrateAddress,
- };
+ // TODO: Obtain which protocol this pool is associated with. For the parachain, there'd need to be some query to see what pools are associated with which parachain protocols. For Tangle networks, it's simply its own protocol. For now, using dummy data.
+ lsProtocolId: LsProtocolId.TANGLE_LOCAL,
+ } satisfies MyLsPoolRow;
});
}, []);
- const handleUnstakeClick = useCallback((poolId: number) => {}, []);
+ const handleUnstakeClick = useCallback((poolId: number) => {
+ setIsStaking(false);
+ setLsPoolId(poolId);
+ }, []);
const columns = [
COLUMN_HELPER.accessor('id', {
@@ -103,6 +116,14 @@ const LsMyPoolsTable: FC = () => {
),
}),
+ COLUMN_HELPER.accessor('lsProtocolId', {
+ header: () => 'Protocol',
+ cell: (props) => {
+ const lsProtocol = getLsProtocolDef(props.getValue());
+
+ return ;
+ },
+ }),
COLUMN_HELPER.accessor('ownerAddress', {
header: () => 'Owner',
cell: (props) => (
@@ -161,6 +182,7 @@ const LsMyPoolsTable: FC = () => {
if (props.row.original.isNominator) {
actionItems.push({
label: 'Update Nominations',
+ // TODO: Implement onClick handler.
onClick: () => void 0,
});
}
@@ -168,6 +190,7 @@ const LsMyPoolsTable: FC = () => {
if (props.row.original.isBouncer) {
actionItems.push({
label: 'Update Commission',
+ // TODO: Implement onClick handler.
onClick: () => void 0,
});
}
@@ -175,22 +198,41 @@ const LsMyPoolsTable: FC = () => {
if (props.row.original.isRoot) {
actionItems.push({
label: 'Update Roles',
+ // TODO: Implement onClick handler.
onClick: () => void 0,
});
}
+ // Sanity check against logic errors.
+ if (hasAnyRole) {
+ assert(actionItems.length > 0);
+ }
+
// If the user has any role in the pool, show the short button style
// to avoid taking up too much space.
const isShortButtonStyle = hasAnyRole;
+ // Disable the stake button if the pool is currently selected,
+ // and the active intent is to unstake.
+ const isUnstakeDisabled =
+ lsPoolId === props.row.original.id && !isStaking;
+
return (
{isShortButtonStyle ? (
-
-
-
+
handleUnstakeClick(props.row.original.id)}
+ tooltip="Unstake"
+ Icon={SubtractCircleLineIcon}
+ />
) : (
- } variant="utility">
+
)}
@@ -224,7 +266,22 @@ const LsMyPoolsTable: FC = () => {
enableSortingRemoval: false,
});
- if (rows.length === 0) {
+ // TODO: Missing error and loading state. Should ideally abstract all these states into an abstract Table component, since it's getting reused in multiple places.
+ if (!isAccountConnected) {
+ return (
+
+ );
+ } else if (rows.length === 0) {
return (
{
+ const [activeAccount] = useActiveAccount();
+
+ return activeAccount?.address !== undefined;
+};
+
+export default useIsAccountConnected;
diff --git a/libs/icons/src/SubtractCircleLineIcon.tsx b/libs/icons/src/SubtractCircleLineIcon.tsx
new file mode 100644
index 000000000..2604970b9
--- /dev/null
+++ b/libs/icons/src/SubtractCircleLineIcon.tsx
@@ -0,0 +1,10 @@
+import { createIcon } from './create-icon';
+import { IconBase } from './types';
+
+export const SubtractCircleLineIcon = (props: IconBase) => {
+ return createIcon({
+ ...props,
+ d: 'M7.00065 14.1654C3.31875 14.1654 0.333984 11.1806 0.333984 7.4987C0.333984 3.8168 3.31875 0.832031 7.00065 0.832031C10.6825 0.832031 13.6673 3.8168 13.6673 7.4987C13.6673 11.1806 10.6825 14.1654 7.00065 14.1654ZM7.00065 12.832C9.94619 12.832 12.334 10.4442 12.334 7.4987C12.334 4.55318 9.94619 2.16536 7.00065 2.16536C4.05513 2.16536 1.66732 4.55318 1.66732 7.4987C1.66732 10.4442 4.05513 12.832 7.00065 12.832ZM3.66732 6.83203H10.334V8.16536H3.66732V6.83203Z',
+ displayName: 'SubtractCircleLineIcon',
+ });
+};
diff --git a/libs/icons/src/index.ts b/libs/icons/src/index.ts
index 27a337a1d..0f15d47ee 100644
--- a/libs/icons/src/index.ts
+++ b/libs/icons/src/index.ts
@@ -149,6 +149,7 @@ export { default as WalletPayIcon } from './WalletPayIcon';
export * from './WaterDropletIcon';
export { default as WebbLogoIcon } from './WebbLogoIcon';
export * from './YouTubeFill';
+export * from './SubtractCircleLineIcon';
// Wallet icons
export * from './wallets';