mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
162 lines
5.1 KiB
TypeScript
162 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import { useStakes } from '@/hooks/useStakes';
|
|
import { DYNAMIC_LINKS, PREFERENCE, VESTING_PATHS } from '@/lib/constants';
|
|
import logger from '@/lib/logger';
|
|
import type { VestingContract } from '@session/staking-api-js/schema';
|
|
import { jsonBigIntReplacer, jsonBigIntReviver } from '@session/util-js/bigint';
|
|
import { usePathname, useRouter } from 'next/navigation';
|
|
import {
|
|
type Dispatch,
|
|
type ReactNode,
|
|
type SetStateAction,
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
} from 'react';
|
|
import { usePreferences } from 'usepref';
|
|
import { isAddress } from 'viem';
|
|
|
|
function saveVestingContract(contract: VestingContract) {
|
|
localStorage.setItem('vestingContract', JSON.stringify(contract, jsonBigIntReplacer));
|
|
}
|
|
|
|
function removeVestingContract() {
|
|
localStorage.removeItem('vestingContract');
|
|
}
|
|
|
|
function loadVestingContract(): VestingContract | null {
|
|
if (typeof window === 'undefined') {
|
|
return null;
|
|
}
|
|
|
|
const storedContract = localStorage.getItem('vestingContract');
|
|
if (!storedContract) return null;
|
|
|
|
return JSON.parse(storedContract, jsonBigIntReviver);
|
|
}
|
|
|
|
type VestingContext = {
|
|
contracts: Array<VestingContract>;
|
|
activeContract: VestingContract | null;
|
|
showVestingSelectionDialog: boolean;
|
|
setShowVestingSelectionDialog: Dispatch<SetStateAction<boolean>>;
|
|
disconnectFromVestingContract: () => void;
|
|
connectToVestingContract: (contract: VestingContract) => void;
|
|
refetch: () => void;
|
|
isLoading: boolean;
|
|
};
|
|
|
|
const Context = createContext<VestingContext | undefined>(undefined);
|
|
|
|
export default function VestingProvider({ children }: { children: ReactNode }) {
|
|
const pathname = usePathname();
|
|
const router = useRouter();
|
|
const { getItem } = usePreferences();
|
|
|
|
const [activeContract, setActiveContract] = useState<VestingContract | null>(
|
|
loadVestingContract()
|
|
);
|
|
const [showVestingSelectionDialog, setShowVestingSelectionDialog] = useState<boolean>(false);
|
|
const [skipped, setSkipped] = useState<boolean>(false);
|
|
|
|
const { vesting, refetch, enabled, isLoading } = useStakes();
|
|
const stakesLoaded = enabled && !isLoading;
|
|
|
|
const disconnectFromVestingContract = useCallback(() => {
|
|
logger.debug('Disconnecting from vesting contract');
|
|
setSkipped(true);
|
|
setActiveContract(null);
|
|
// setShowVestingSelectionDialog must be called after setActiveContract or the dialog will pop up for a moment
|
|
setShowVestingSelectionDialog(false);
|
|
removeVestingContract();
|
|
|
|
if (pathname.startsWith(DYNAMIC_LINKS.vestedStakes.href)) {
|
|
router.push(DYNAMIC_LINKS.myStakes.href);
|
|
}
|
|
}, [pathname, router]);
|
|
|
|
const connectToVestingContract = useCallback(
|
|
(contract: VestingContract) => {
|
|
logger.debug(`Connecting to vesting contract: ${contract.address}`);
|
|
setShowVestingSelectionDialog(false);
|
|
setActiveContract(contract);
|
|
saveVestingContract(contract);
|
|
|
|
if (pathname.startsWith(DYNAMIC_LINKS.myStakes.href)) {
|
|
router.push(DYNAMIC_LINKS.vestedStakes.href);
|
|
}
|
|
},
|
|
[pathname, router]
|
|
);
|
|
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies(pathname.startsWith): Don't re-trigger when pathname changes
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies(router.push): Don't re-trigger when router changes
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies(getItem): Don't re-trigger getItem changes
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies(skipped): Don't re-trigger when skip changes
|
|
useEffect(() => {
|
|
if (stakesLoaded) {
|
|
if (
|
|
!activeContract &&
|
|
vesting?.length &&
|
|
!getItem<boolean>(PREFERENCE.SKIP_VESTING_POPUP_ON_STARTUP) &&
|
|
VESTING_PATHS.some((path) => pathname.startsWith(path))
|
|
) {
|
|
if (!skipped) {
|
|
setShowVestingSelectionDialog(true);
|
|
}
|
|
if (pathname.startsWith(DYNAMIC_LINKS.vestedStakes.href)) {
|
|
router.push(DYNAMIC_LINKS.myStakes.href);
|
|
}
|
|
} else {
|
|
if (activeContract && pathname.startsWith(DYNAMIC_LINKS.myStakes.href)) {
|
|
router.push(DYNAMIC_LINKS.vestedStakes.href);
|
|
}
|
|
}
|
|
}
|
|
}, [activeContract, vesting, stakesLoaded]);
|
|
|
|
return (
|
|
<Context.Provider
|
|
value={{
|
|
contracts: vesting,
|
|
activeContract,
|
|
showVestingSelectionDialog,
|
|
setShowVestingSelectionDialog,
|
|
disconnectFromVestingContract,
|
|
connectToVestingContract,
|
|
refetch,
|
|
isLoading,
|
|
}}
|
|
>
|
|
{children}
|
|
</Context.Provider>
|
|
);
|
|
}
|
|
|
|
export const useVesting = () => {
|
|
const context = useContext(Context);
|
|
|
|
if (context === undefined) {
|
|
throw new Error('useVesting must be used inside VestingProvider');
|
|
}
|
|
|
|
return context;
|
|
};
|
|
|
|
export const useActiveVestingContract = () => useVesting().activeContract;
|
|
|
|
export const useActiveVestingContractAddress = () => useVesting().activeContract?.address;
|
|
|
|
export const useConnectedVestingContract = () => {
|
|
const activeContract = useActiveVestingContract();
|
|
|
|
if (!activeContract?.address || !isAddress(activeContract.address)) {
|
|
throw new Error('No active vesting contract address');
|
|
}
|
|
|
|
return activeContract;
|
|
};
|