diff --git a/src/components/RegisterName.tsx b/src/components/RegisterName.tsx index 9a3865d..f449bca 100644 --- a/src/components/RegisterName.tsx +++ b/src/components/RegisterName.tsx @@ -18,12 +18,17 @@ import { Spacer, useGlobal, } from 'qapp-core'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner'; import CheckIcon from '@mui/icons-material/Check'; import ErrorIcon from '@mui/icons-material/Error'; -import { useSetAtom } from 'jotai'; -import { namesAtom, pendingTxsAtom } from '../state/global/names'; +import { useAtom, useSetAtom } from 'jotai'; +import { + forSaleAtom, + namesAtom, + pendingTxsAtom, + primaryNameAtom, +} from '../state/global/names'; import { Availability } from '../interfaces'; const Label = styled('label')` @@ -38,7 +43,9 @@ const RegisterName = () => { const [isOpen, setIsOpen] = useState(false); const balance = useGlobal().auth.balance; const setNames = useSetAtom(namesAtom); - + const [namesForSale] = useAtom(forSaleAtom); + const [primaryName] = useAtom(primaryNameAtom); + const [pendingTxs] = useAtom(pendingTxsAtom); const address = useGlobal().auth.address; const [nameValue, setNameValue] = useState(''); const [isNameAvailable, setIsNameAvailable] = useState( @@ -49,6 +56,25 @@ const RegisterName = () => { const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false); const theme = useTheme(); const [nameFee, setNameFee] = useState(null); + const isPrimaryNameForSale = useMemo(() => { + if (!primaryName) return false; + const findPendingNameSellTx = pendingTxs?.['SELL_NAME']; + let isOnSale = false; + if (findPendingNameSellTx) { + Object.values(findPendingNameSellTx).forEach((value) => { + if (value?.name === primaryName) { + isOnSale = true; + return; + } + }); + } + if (isOnSale) return true; + const findNameIndex = namesForSale?.findIndex( + (item) => item?.name === primaryName + ); + if (findNameIndex === -1) return false; + return true; + }, [namesForSale, primaryName, pendingTxs]); const registerNameFunc = async () => { if (!address) return; const loadId = showLoading('Registering name...please wait'); @@ -142,7 +168,7 @@ const RegisterName = () => { return ( <> @@ -384,6 +399,7 @@ function rowContent( color="error" size="small" onClick={() => handleCancel(row.name)} + disabled={isNameCurrentlyDoingATx} > Cancel Sell @@ -391,6 +407,7 @@ function rowContent( @@ -406,6 +423,8 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => { const setNames = useSetAtom(namesAtom); const { auth } = useGlobal(); const [namesForSale, setNamesForSale] = useAtom(forSaleAtom); + const [pendingTxs] = useAtom(pendingTxsAtom); + const modalFunctions = useModal<{ name: string }>(); const modalFunctionsUpdateName = useModal(); const modalFunctionsAvatar = useModal<{ name: string; hasAvatar: boolean }>(); @@ -435,8 +454,12 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => { data={namesToDisplay} components={VirtuosoTableComponents} fixedHeaderContent={fixedHeaderContent} - itemContent={(index, row) => - rowContent( + itemContent={(index, row) => { + const isNameCurrentlyDoingATx = isNamePendingTx( + row?.name, + pendingTxs + ); + return rowContent( index, row, primaryName, @@ -449,9 +472,10 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => { modalFunctionsSellName, setPendingTxs, setNames, - setNamesForSale - ) - } + setNamesForSale, + isNameCurrentlyDoingATx + ); + }} /> {modalFunctions?.isShow && ( { const [namesForSale] = useAtom(forSaleAtom); + const [pendingTxs] = useAtom(pendingTxsAtom); + const [primaryName] = useAtom(primaryNameAtom); + const [sortBy, setSortBy] = useState('name'); const [sortDirection, setSortDirection] = useState('asc'); const [filterValue, setFilterValue] = useState(''); @@ -41,6 +48,26 @@ export const Market = () => { }); }, [namesForSale, sortBy, sortDirection, filterValue]); + const isPrimaryNameForSale = useMemo(() => { + if (!primaryName) return false; + const findPendingNameSellTx = pendingTxs?.['SELL_NAME']; + let isOnSale = false; + if (findPendingNameSellTx) { + Object.values(findPendingNameSellTx).forEach((value) => { + if (value?.name === primaryName) { + isOnSale = true; + return; + } + }); + } + if (isOnSale) return true; + const findNameIndex = namesForSale?.findIndex( + (item) => item?.name === primaryName + ); + if (findNameIndex === -1) return false; + return true; + }, [namesForSale, primaryName, pendingTxs]); + useEffect(() => { const handler = setTimeout(() => { setFilterValue(value); @@ -90,6 +117,7 @@ export const Market = () => { sortBy={sortBy} sortDirection={sortDirection} handleSort={handleSort} + isPrimaryNameForSale={isPrimaryNameForSale} /> ); diff --git a/src/state/global/names.ts b/src/state/global/names.ts index 2473eec..5e5ef0d 100644 --- a/src/state/global/names.ts +++ b/src/state/global/names.ts @@ -1,5 +1,23 @@ import { atom } from 'jotai'; +export const isNamePendingTx = ( + name: string, + pendingTxs: PendingTxsState +): boolean => { + for (const category of Object.keys(pendingTxs) as TransactionCategory[]) { + const txMap = pendingTxs[category]; + if (!txMap) continue; + + for (const tx of Object.values(txMap)) { + if (tx.name === name) { + return true; + } + } + } + + return false; +}; + interface AdditionalFields { callback: () => void; status: 'PENDING'; @@ -35,7 +53,7 @@ interface UpdateNameTransaction { newData: string; } -interface SellNameTransaction { +export interface SellNameTransaction { type: 'SELL_NAME'; timestamp: number; reference: string;