mirror of
https://github.com/Qortal/names.git
synced 2025-06-15 18:51:21 +00:00
added conditions for actions
This commit is contained in:
parent
d1233cc1ad
commit
18151bfa9b
@ -18,12 +18,17 @@ import {
|
|||||||
Spacer,
|
Spacer,
|
||||||
useGlobal,
|
useGlobal,
|
||||||
} from 'qapp-core';
|
} from 'qapp-core';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner';
|
import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner';
|
||||||
import CheckIcon from '@mui/icons-material/Check';
|
import CheckIcon from '@mui/icons-material/Check';
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useAtom, useSetAtom } from 'jotai';
|
||||||
import { namesAtom, pendingTxsAtom } from '../state/global/names';
|
import {
|
||||||
|
forSaleAtom,
|
||||||
|
namesAtom,
|
||||||
|
pendingTxsAtom,
|
||||||
|
primaryNameAtom,
|
||||||
|
} from '../state/global/names';
|
||||||
import { Availability } from '../interfaces';
|
import { Availability } from '../interfaces';
|
||||||
|
|
||||||
const Label = styled('label')`
|
const Label = styled('label')`
|
||||||
@ -38,7 +43,9 @@ const RegisterName = () => {
|
|||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const balance = useGlobal().auth.balance;
|
const balance = useGlobal().auth.balance;
|
||||||
const setNames = useSetAtom(namesAtom);
|
const setNames = useSetAtom(namesAtom);
|
||||||
|
const [namesForSale] = useAtom(forSaleAtom);
|
||||||
|
const [primaryName] = useAtom(primaryNameAtom);
|
||||||
|
const [pendingTxs] = useAtom(pendingTxsAtom);
|
||||||
const address = useGlobal().auth.address;
|
const address = useGlobal().auth.address;
|
||||||
const [nameValue, setNameValue] = useState('');
|
const [nameValue, setNameValue] = useState('');
|
||||||
const [isNameAvailable, setIsNameAvailable] = useState<Availability>(
|
const [isNameAvailable, setIsNameAvailable] = useState<Availability>(
|
||||||
@ -49,6 +56,25 @@ const RegisterName = () => {
|
|||||||
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
|
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [nameFee, setNameFee] = useState<number | null>(null);
|
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 () => {
|
const registerNameFunc = async () => {
|
||||||
if (!address) return;
|
if (!address) return;
|
||||||
const loadId = showLoading('Registering name...please wait');
|
const loadId = showLoading('Registering name...please wait');
|
||||||
@ -142,7 +168,7 @@ const RegisterName = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
// disabled={!nameValue?.trim()}
|
disabled={isPrimaryNameForSale}
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -94,7 +94,8 @@ function rowContent(
|
|||||||
row: NamesForSale,
|
row: NamesForSale,
|
||||||
setPendingTxs: SetPendingTxs,
|
setPendingTxs: SetPendingTxs,
|
||||||
setNames: SetNames,
|
setNames: SetNames,
|
||||||
setNamesForSale: SetNamesForSale
|
setNamesForSale: SetNamesForSale,
|
||||||
|
isPrimaryNameForSale: boolean
|
||||||
) {
|
) {
|
||||||
const handleBuy = async (name: string) => {
|
const handleBuy = async (name: string) => {
|
||||||
const loadId = showLoading('Attempting to purchase name...please wait');
|
const loadId = showLoading('Attempting to purchase name...please wait');
|
||||||
@ -146,6 +147,7 @@ function rowContent(
|
|||||||
<TableCell>{row.salePrice}</TableCell>
|
<TableCell>{row.salePrice}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={isPrimaryNameForSale}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => handleBuy(row.name)}
|
onClick={() => handleBuy(row.name)}
|
||||||
@ -162,6 +164,7 @@ interface ForSaleTable {
|
|||||||
sortDirection: SortDirection;
|
sortDirection: SortDirection;
|
||||||
sortBy: SortBy;
|
sortBy: SortBy;
|
||||||
handleSort: (sortBy: SortBy) => void;
|
handleSort: (sortBy: SortBy) => void;
|
||||||
|
isPrimaryNameForSale: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ForSaleTable = ({
|
export const ForSaleTable = ({
|
||||||
@ -169,6 +172,7 @@ export const ForSaleTable = ({
|
|||||||
sortDirection,
|
sortDirection,
|
||||||
sortBy,
|
sortBy,
|
||||||
handleSort,
|
handleSort,
|
||||||
|
isPrimaryNameForSale,
|
||||||
}: ForSaleTable) => {
|
}: ForSaleTable) => {
|
||||||
const setNames = useSetAtom(namesAtom);
|
const setNames = useSetAtom(namesAtom);
|
||||||
const setNamesForSale = useSetAtom(forSaleAtom);
|
const setNamesForSale = useSetAtom(forSaleAtom);
|
||||||
@ -188,7 +192,14 @@ export const ForSaleTable = ({
|
|||||||
fixedHeaderContent(sortBy, sortDirection, handleSort)
|
fixedHeaderContent(sortBy, sortDirection, handleSort)
|
||||||
}
|
}
|
||||||
itemContent={(index, row: NamesForSale) =>
|
itemContent={(index, row: NamesForSale) =>
|
||||||
rowContent(index, row, setPendingTxs, setNames, setNamesForSale)
|
rowContent(
|
||||||
|
index,
|
||||||
|
row,
|
||||||
|
setPendingTxs,
|
||||||
|
setNames,
|
||||||
|
setNamesForSale,
|
||||||
|
isPrimaryNameForSale
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -26,6 +26,7 @@ import { TableVirtuoso, TableComponents } from 'react-virtuoso';
|
|||||||
import {
|
import {
|
||||||
forceRefreshAtom,
|
forceRefreshAtom,
|
||||||
forSaleAtom,
|
forSaleAtom,
|
||||||
|
isNamePendingTx,
|
||||||
Names,
|
Names,
|
||||||
namesAtom,
|
namesAtom,
|
||||||
NamesForSale,
|
NamesForSale,
|
||||||
@ -99,9 +100,14 @@ function fixedHeaderContent() {
|
|||||||
interface ManageAvatarProps {
|
interface ManageAvatarProps {
|
||||||
name: string;
|
name: string;
|
||||||
modalFunctionsAvatar: ModalFunctionsAvatar;
|
modalFunctionsAvatar: ModalFunctionsAvatar;
|
||||||
|
isNameCurrentlyDoingATx?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ManageAvatar = ({ name, modalFunctionsAvatar }: ManageAvatarProps) => {
|
const ManageAvatar = ({
|
||||||
|
name,
|
||||||
|
modalFunctionsAvatar,
|
||||||
|
isNameCurrentlyDoingATx,
|
||||||
|
}: ManageAvatarProps) => {
|
||||||
const { setHasAvatar, getHasAvatar } = usePendingTxs();
|
const { setHasAvatar, getHasAvatar } = usePendingTxs();
|
||||||
const [refresh] = useAtom(refreshAtom); // just to subscribe
|
const [refresh] = useAtom(refreshAtom); // just to subscribe
|
||||||
const [hasAvatarState, setHasAvatarState] = useState<boolean | null>(null);
|
const [hasAvatarState, setHasAvatarState] = useState<boolean | null>(null);
|
||||||
@ -146,7 +152,7 @@ const ManageAvatar = ({ name, modalFunctionsAvatar }: ManageAvatarProps) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
disabled={hasAvatarState === null}
|
disabled={hasAvatarState === null || isNameCurrentlyDoingATx}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
modalFunctionsAvatar.show({ name, hasAvatar: Boolean(hasAvatarState) })
|
modalFunctionsAvatar.show({ name, hasAvatar: Boolean(hasAvatarState) })
|
||||||
}
|
}
|
||||||
@ -179,7 +185,8 @@ function rowContent(
|
|||||||
modalFunctionsSellName: ReturnType<typeof useModal>,
|
modalFunctionsSellName: ReturnType<typeof useModal>,
|
||||||
setPendingTxs: SetPendingTxs,
|
setPendingTxs: SetPendingTxs,
|
||||||
setNames: SetNames,
|
setNames: SetNames,
|
||||||
setNamesForSale: SetNamesForSale
|
setNamesForSale: SetNamesForSale,
|
||||||
|
isNameCurrentlyDoingATx: boolean
|
||||||
) {
|
) {
|
||||||
const handleUpdate = async (name: string) => {
|
const handleUpdate = async (name: string) => {
|
||||||
if (name === primaryName && numberOfNames > 1) {
|
if (name === primaryName && numberOfNames > 1) {
|
||||||
@ -366,6 +373,10 @@ function rowContent(
|
|||||||
color={primaryName === row.name ? 'warning' : 'primary'}
|
color={primaryName === row.name ? 'warning' : 'primary'}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
|
disabled={
|
||||||
|
(row?.name === primaryName && numberOfNames > 1) ||
|
||||||
|
isNameCurrentlyDoingATx
|
||||||
|
}
|
||||||
onClick={() => handleUpdate(row.name)}
|
onClick={() => handleUpdate(row.name)}
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
@ -376,6 +387,10 @@ function rowContent(
|
|||||||
size="small"
|
size="small"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={() => handleSell(row.name)}
|
onClick={() => handleSell(row.name)}
|
||||||
|
disabled={
|
||||||
|
(row?.name === primaryName && numberOfNames > 1) ||
|
||||||
|
isNameCurrentlyDoingATx
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Sell
|
Sell
|
||||||
</Button>
|
</Button>
|
||||||
@ -384,6 +399,7 @@ function rowContent(
|
|||||||
color="error"
|
color="error"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => handleCancel(row.name)}
|
onClick={() => handleCancel(row.name)}
|
||||||
|
disabled={isNameCurrentlyDoingATx}
|
||||||
>
|
>
|
||||||
Cancel Sell
|
Cancel Sell
|
||||||
</Button>
|
</Button>
|
||||||
@ -391,6 +407,7 @@ function rowContent(
|
|||||||
<ManageAvatar
|
<ManageAvatar
|
||||||
name={row.name}
|
name={row.name}
|
||||||
modalFunctionsAvatar={modalFunctionsAvatar}
|
modalFunctionsAvatar={modalFunctionsAvatar}
|
||||||
|
isNameCurrentlyDoingATx={isNameCurrentlyDoingATx}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@ -406,6 +423,8 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => {
|
|||||||
const setNames = useSetAtom(namesAtom);
|
const setNames = useSetAtom(namesAtom);
|
||||||
const { auth } = useGlobal();
|
const { auth } = useGlobal();
|
||||||
const [namesForSale, setNamesForSale] = useAtom(forSaleAtom);
|
const [namesForSale, setNamesForSale] = useAtom(forSaleAtom);
|
||||||
|
const [pendingTxs] = useAtom(pendingTxsAtom);
|
||||||
|
|
||||||
const modalFunctions = useModal<{ name: string }>();
|
const modalFunctions = useModal<{ name: string }>();
|
||||||
const modalFunctionsUpdateName = useModal();
|
const modalFunctionsUpdateName = useModal();
|
||||||
const modalFunctionsAvatar = useModal<{ name: string; hasAvatar: boolean }>();
|
const modalFunctionsAvatar = useModal<{ name: string; hasAvatar: boolean }>();
|
||||||
@ -435,8 +454,12 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => {
|
|||||||
data={namesToDisplay}
|
data={namesToDisplay}
|
||||||
components={VirtuosoTableComponents}
|
components={VirtuosoTableComponents}
|
||||||
fixedHeaderContent={fixedHeaderContent}
|
fixedHeaderContent={fixedHeaderContent}
|
||||||
itemContent={(index, row) =>
|
itemContent={(index, row) => {
|
||||||
rowContent(
|
const isNameCurrentlyDoingATx = isNamePendingTx(
|
||||||
|
row?.name,
|
||||||
|
pendingTxs
|
||||||
|
);
|
||||||
|
return rowContent(
|
||||||
index,
|
index,
|
||||||
row,
|
row,
|
||||||
primaryName,
|
primaryName,
|
||||||
@ -449,9 +472,10 @@ export const NameTable = ({ names, primaryName }: NameTableProps) => {
|
|||||||
modalFunctionsSellName,
|
modalFunctionsSellName,
|
||||||
setPendingTxs,
|
setPendingTxs,
|
||||||
setNames,
|
setNames,
|
||||||
setNamesForSale
|
setNamesForSale,
|
||||||
)
|
isNameCurrentlyDoingATx
|
||||||
}
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{modalFunctions?.isShow && (
|
{modalFunctions?.isShow && (
|
||||||
<Dialog
|
<Dialog
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
import { Box, TextField } from '@mui/material';
|
import { Box, TextField } from '@mui/material';
|
||||||
import { ForSaleTable } from '../components/Tables/ForSaleTable';
|
import { ForSaleTable } from '../components/Tables/ForSaleTable';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
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 { useAtom } from 'jotai';
|
||||||
import { SortBy, SortDirection } from '../interfaces';
|
import { SortBy, SortDirection } from '../interfaces';
|
||||||
|
|
||||||
export const Market = () => {
|
export const Market = () => {
|
||||||
const [namesForSale] = useAtom(forSaleAtom);
|
const [namesForSale] = useAtom(forSaleAtom);
|
||||||
|
const [pendingTxs] = useAtom(pendingTxsAtom);
|
||||||
|
const [primaryName] = useAtom(primaryNameAtom);
|
||||||
|
|
||||||
const [sortBy, setSortBy] = useState<SortBy>('name');
|
const [sortBy, setSortBy] = useState<SortBy>('name');
|
||||||
const [sortDirection, setSortDirection] = useState<SortDirection>('asc');
|
const [sortDirection, setSortDirection] = useState<SortDirection>('asc');
|
||||||
const [filterValue, setFilterValue] = useState('');
|
const [filterValue, setFilterValue] = useState('');
|
||||||
@ -41,6 +48,26 @@ export const Market = () => {
|
|||||||
});
|
});
|
||||||
}, [namesForSale, sortBy, sortDirection, filterValue]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
||||||
setFilterValue(value);
|
setFilterValue(value);
|
||||||
@ -90,6 +117,7 @@ export const Market = () => {
|
|||||||
sortBy={sortBy}
|
sortBy={sortBy}
|
||||||
sortDirection={sortDirection}
|
sortDirection={sortDirection}
|
||||||
handleSort={handleSort}
|
handleSort={handleSort}
|
||||||
|
isPrimaryNameForSale={isPrimaryNameForSale}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
import { atom } from 'jotai';
|
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 {
|
interface AdditionalFields {
|
||||||
callback: () => void;
|
callback: () => void;
|
||||||
status: 'PENDING';
|
status: 'PENDING';
|
||||||
@ -35,7 +53,7 @@ interface UpdateNameTransaction {
|
|||||||
newData: string;
|
newData: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SellNameTransaction {
|
export interface SellNameTransaction {
|
||||||
type: 'SELL_NAME';
|
type: 'SELL_NAME';
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
reference: string;
|
reference: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user