added conditions for actions

This commit is contained in:
PhilReact 2025-05-20 15:47:14 +03:00
parent d1233cc1ad
commit 18151bfa9b
5 changed files with 124 additions and 17 deletions

View File

@ -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<Availability>(
@ -49,6 +56,25 @@ const RegisterName = () => {
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
const theme = useTheme();
const [nameFee, setNameFee] = useState<number | null>(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 (
<>
<Button
// disabled={!nameValue?.trim()}
disabled={isPrimaryNameForSale}
onClick={() => setIsOpen(true)}
variant="outlined"
sx={{

View File

@ -94,7 +94,8 @@ function rowContent(
row: NamesForSale,
setPendingTxs: SetPendingTxs,
setNames: SetNames,
setNamesForSale: SetNamesForSale
setNamesForSale: SetNamesForSale,
isPrimaryNameForSale: boolean
) {
const handleBuy = async (name: string) => {
const loadId = showLoading('Attempting to purchase name...please wait');
@ -146,6 +147,7 @@ function rowContent(
<TableCell>{row.salePrice}</TableCell>
<TableCell>
<Button
disabled={isPrimaryNameForSale}
variant="contained"
size="small"
onClick={() => handleBuy(row.name)}
@ -162,6 +164,7 @@ interface ForSaleTable {
sortDirection: SortDirection;
sortBy: SortBy;
handleSort: (sortBy: SortBy) => void;
isPrimaryNameForSale: boolean;
}
export const ForSaleTable = ({
@ -169,6 +172,7 @@ export const ForSaleTable = ({
sortDirection,
sortBy,
handleSort,
isPrimaryNameForSale,
}: ForSaleTable) => {
const setNames = useSetAtom(namesAtom);
const setNamesForSale = useSetAtom(forSaleAtom);
@ -188,7 +192,14 @@ export const ForSaleTable = ({
fixedHeaderContent(sortBy, sortDirection, handleSort)
}
itemContent={(index, row: NamesForSale) =>
rowContent(index, row, setPendingTxs, setNames, setNamesForSale)
rowContent(
index,
row,
setPendingTxs,
setNames,
setNamesForSale,
isPrimaryNameForSale
)
}
/>
</Paper>

View File

@ -26,6 +26,7 @@ import { TableVirtuoso, TableComponents } from 'react-virtuoso';
import {
forceRefreshAtom,
forSaleAtom,
isNamePendingTx,
Names,
namesAtom,
NamesForSale,
@ -99,9 +100,14 @@ function fixedHeaderContent() {
interface ManageAvatarProps {
name: string;
modalFunctionsAvatar: ModalFunctionsAvatar;
isNameCurrentlyDoingATx?: boolean;
}
const ManageAvatar = ({ name, modalFunctionsAvatar }: ManageAvatarProps) => {
const ManageAvatar = ({
name,
modalFunctionsAvatar,
isNameCurrentlyDoingATx,
}: ManageAvatarProps) => {
const { setHasAvatar, getHasAvatar } = usePendingTxs();
const [refresh] = useAtom(refreshAtom); // just to subscribe
const [hasAvatarState, setHasAvatarState] = useState<boolean | null>(null);
@ -146,7 +152,7 @@ const ManageAvatar = ({ name, modalFunctionsAvatar }: ManageAvatarProps) => {
<Button
variant="outlined"
size="small"
disabled={hasAvatarState === null}
disabled={hasAvatarState === null || isNameCurrentlyDoingATx}
onClick={() =>
modalFunctionsAvatar.show({ name, hasAvatar: Boolean(hasAvatarState) })
}
@ -179,7 +185,8 @@ function rowContent(
modalFunctionsSellName: ReturnType<typeof useModal>,
setPendingTxs: SetPendingTxs,
setNames: SetNames,
setNamesForSale: SetNamesForSale
setNamesForSale: SetNamesForSale,
isNameCurrentlyDoingATx: boolean
) {
const handleUpdate = async (name: string) => {
if (name === primaryName && numberOfNames > 1) {
@ -366,6 +373,10 @@ function rowContent(
color={primaryName === row.name ? 'warning' : 'primary'}
variant="outlined"
size="small"
disabled={
(row?.name === primaryName && numberOfNames > 1) ||
isNameCurrentlyDoingATx
}
onClick={() => handleUpdate(row.name)}
>
Update
@ -376,6 +387,10 @@ function rowContent(
size="small"
variant="outlined"
onClick={() => handleSell(row.name)}
disabled={
(row?.name === primaryName && numberOfNames > 1) ||
isNameCurrentlyDoingATx
}
>
Sell
</Button>
@ -384,6 +399,7 @@ function rowContent(
color="error"
size="small"
onClick={() => handleCancel(row.name)}
disabled={isNameCurrentlyDoingATx}
>
Cancel Sell
</Button>
@ -391,6 +407,7 @@ function rowContent(
<ManageAvatar
name={row.name}
modalFunctionsAvatar={modalFunctionsAvatar}
isNameCurrentlyDoingATx={isNameCurrentlyDoingATx}
/>
</Box>
</TableCell>
@ -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 && (
<Dialog

View File

@ -1,12 +1,19 @@
import { Box, TextField } from '@mui/material';
import { ForSaleTable } from '../components/Tables/ForSaleTable';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { forSaleAtom } from '../state/global/names';
import {
forSaleAtom,
pendingTxsAtom,
primaryNameAtom,
} from '../state/global/names';
import { useAtom } from 'jotai';
import { SortBy, SortDirection } from '../interfaces';
export const Market = () => {
const [namesForSale] = useAtom(forSaleAtom);
const [pendingTxs] = useAtom(pendingTxsAtom);
const [primaryName] = useAtom(primaryNameAtom);
const [sortBy, setSortBy] = useState<SortBy>('name');
const [sortDirection, setSortDirection] = useState<SortDirection>('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}
/>
</div>
);

View File

@ -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;