From dc8946c17d0a22d9e3f8b2c5360867b0a294fbe6 Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 9 Nov 2022 18:59:23 +0500
Subject: [PATCH 01/10] Add Nft detail screen
---
src/app/hooks/useNftDataSelector.ts | 14 +
src/app/hooks/useNftReducer.ts | 21 ++
src/app/routes/index.tsx | 5 +
src/app/screens/nftDashboard/index.tsx | 125 +++----
src/app/screens/nftDashboard/nft.tsx | 27 +-
src/app/screens/nftDashboard/nftImage.tsx | 27 +-
src/app/screens/nftDetail/descriptionTile.tsx | 36 ++
src/app/screens/nftDetail/index.tsx | 339 ++++++++++++++++++
src/app/screens/nftDetail/nftAttribute.tsx | 38 ++
src/app/stores/index.ts | 3 +
.../stores/nftData/actions/actionCreator.ts | 10 +
src/app/stores/nftData/actions/types.ts | 14 +
src/app/stores/nftData/reducer.ts | 23 ++
src/locales/en.json | 19 +
14 files changed, 609 insertions(+), 92 deletions(-)
create mode 100644 src/app/hooks/useNftDataSelector.ts
create mode 100644 src/app/hooks/useNftReducer.ts
create mode 100644 src/app/screens/nftDetail/descriptionTile.tsx
create mode 100644 src/app/screens/nftDetail/index.tsx
create mode 100644 src/app/screens/nftDetail/nftAttribute.tsx
create mode 100644 src/app/stores/nftData/actions/actionCreator.ts
create mode 100644 src/app/stores/nftData/actions/types.ts
create mode 100644 src/app/stores/nftData/reducer.ts
diff --git a/src/app/hooks/useNftDataSelector.ts b/src/app/hooks/useNftDataSelector.ts
new file mode 100644
index 000000000..a9a4309ed
--- /dev/null
+++ b/src/app/hooks/useNftDataSelector.ts
@@ -0,0 +1,14 @@
+import { StoreState } from '@stores/index';
+import { useSelector } from 'react-redux';
+
+const useNftDataSelector = () => {
+ const nftDataState = useSelector((state: StoreState) => ({
+ ...state.nftDataState,
+ }));
+
+ return {
+ ...nftDataState,
+ };
+};
+
+export default useNftDataSelector;
diff --git a/src/app/hooks/useNftReducer.ts b/src/app/hooks/useNftReducer.ts
new file mode 100644
index 000000000..dee6e9f3c
--- /dev/null
+++ b/src/app/hooks/useNftReducer.ts
@@ -0,0 +1,21 @@
+import { NftDetailResponse } from '@secretkeylabs/xverse-core/types';
+import { setNftDataAction } from '@stores/nftData/actions/actionCreator';
+import { useDispatch } from 'react-redux';
+import useNftDataSelector from './useNftDataSelector';
+
+const useNftDataReducer = () => {
+ const { nftData } = useNftDataSelector();
+ const dispatch = useDispatch();
+ const storeNftData = (data:NftDetailResponse) => {
+ if (data && !nftData.includes(data.data)) {
+ const modifiedNftList = [...nftData];
+ modifiedNftList.push(data.data);
+ dispatch(setNftDataAction(modifiedNftList));
+ }
+ };
+ return {
+ storeNftData,
+ };
+};
+
+export default useNftDataReducer;
diff --git a/src/app/routes/index.tsx b/src/app/routes/index.tsx
index 6ee439eb1..f9c057e73 100644
--- a/src/app/routes/index.tsx
+++ b/src/app/routes/index.tsx
@@ -21,6 +21,7 @@ import RestoreWallet from '@screens/restoreWallet';
import ForgotPassword from '@screens/forgotPassword';
import BackupWalletSteps from '@screens/backupWalletSteps';
import NftDashboard from '@screens/nftDashboard';
+import NftDetailScreen from '@screens/nftDetail';
const router = createHashRouter([
{
@@ -111,6 +112,10 @@ const router = createHashRouter([
path: 'nft-dashboard',
element: ,
},
+ {
+ path: 'nft-dashboard/nft-detail/:id',
+ element: ,
+ },
],
},
]);
diff --git a/src/app/screens/nftDashboard/index.tsx b/src/app/screens/nftDashboard/index.tsx
index bc3528694..238f17032 100644
--- a/src/app/screens/nftDashboard/index.tsx
+++ b/src/app/screens/nftDashboard/index.tsx
@@ -20,16 +20,16 @@ import ShareDialog from '@components/shareNft';
import Nft from './nft';
const Container = styled.div`
-display: flex;
-flex-direction: column;
-flex: 1;
-margin-left: 5%;
-margin-right: 5%;
-margin-bottom: 5%;
-overflow-y: auto;
-&::-webkit-scrollbar {
- display: none;
-}
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ margin-left: 5%;
+ margin-right: 5%;
+ margin-bottom: 5%;
+ overflow-y: auto;
+ &::-webkit-scrollbar {
+ display: none;
+ }
`;
const GridContainer = styled.div((props) => ({
@@ -89,8 +89,8 @@ const NoCollectiblesText = styled.h1((props) => ({
}));
const BarLoaderContainer = styled.div((props) => ({
- display: 'flex',
marginTop: props.theme.spacing(5),
+ maxWidth: 300,
}));
function NftDashboard() {
@@ -103,11 +103,9 @@ function NftDashboard() {
const [nftTotal, setNftTotal] = useState(0);
const [showShareNftOptions, setShowNftOptions] = useState(false);
- const {
- isLoading, data,
- } = useQuery(
+ const { isLoading, data } = useQuery(
['nft-meta-data', { stxAddress, network, offset: offset.current }],
- async () => getNftsData(stxAddress, network, offset.current),
+ async () => getNftsData('SP2VC4CXTWYRZEV7MSGXPNHE739N14ECQWX8JP2BF', network, offset.current),
);
useEffect(() => {
@@ -120,39 +118,20 @@ function NftDashboard() {
navigate('/account-list');
};
- const loader = (
-
-
-
- );
-
const openInGalleryView = async () => {
await chrome.tabs.create({
url: chrome.runtime.getURL('options.html#/nft-dashboard'),
});
};
- const collectiblesCard = (
-
- {t('COLLECTIBLES')}
- {isLoading ? loader
- : {`${nftTotal} ${t('ITEMS')}`}}
-
-
- );
-
- const nftListView = (
- nftTotal === 0 ? (
-
- {t('NO_COLLECTIBLES')}
-
- ) : (
-
- { nftList.map((nft) => (
-
- ))}
-
- )
+ const nftListView = nftTotal === 0 ? (
+ {t('NO_COLLECTIBLES')}
+ ) : (
+
+ {nftList.map((nft) => (
+
+ ))}
+
);
const onSharePress = () => {
@@ -167,27 +146,6 @@ function NftDashboard() {
navigate('/receive/STX');
};
- const buttons = (
-
-
-
- {showShareNftOptions && }
-
- );
-
- const showLoader = (
-
-
-
- );
-
return (
<>
@@ -195,9 +153,44 @@ function NftDashboard() {
- {collectiblesCard}
- {buttons}
- {isLoading ? showLoader : nftListView}
+
+ {t('COLLECTIBLES')}
+ {isLoading ? (
+
+
+
+ ) : (
+ {`${nftTotal} ${t('ITEMS')}`}
+ )}
+
+
+
+
+
+ {showShareNftOptions && (
+
+ )}
+
+ {isLoading ? (
+
+
+
+ ) : (
+ nftListView
+ )}
diff --git a/src/app/screens/nftDashboard/nft.tsx b/src/app/screens/nftDashboard/nft.tsx
index 587e389f9..e46357577 100644
--- a/src/app/screens/nftDashboard/nft.tsx
+++ b/src/app/screens/nftDashboard/nft.tsx
@@ -5,6 +5,7 @@ import { NonFungibleToken, getBnsNftName } from '@secretkeylabs/xverse-core/type
import { BNS_CONTRACT } from '@utils/constants';
import NftUser from '@assets/img/nftDashboard/nft_user.svg';
import { useNavigate } from 'react-router-dom';
+import useNftDataReducer from '@hooks/useNftReducer';
import NftImage from './nftImage';
interface Props {
@@ -42,6 +43,8 @@ const GridItemContainer = styled.button((props) => ({
function Nft({ asset }: Props) {
const navigate = useNavigate();
+ const { storeNftData } = useNftDataReducer();
+ const url = `${asset.asset_identifier}::${asset.value.repr}`;
const { data } = useQuery(
['nft-meta-data', asset.asset_identifier],
async () => {
@@ -63,30 +66,26 @@ function Nft({ asset }: Props) {
}
}
- const nftName = (
- {getName()}
- );
-
- const bnsPlaceholder = (
-
-
-
- );
-
const handleOnClick = () => {
-
+ storeNftData(data);
+ if (asset.asset_identifier !== BNS_CONTRACT) {
+ navigate(`nft-detail/${url}`);
+ }
};
return (
- {asset.asset_identifier === BNS_CONTRACT ? bnsPlaceholder : (
+ {asset.asset_identifier === BNS_CONTRACT ? (
+
+
+
+ ) : (
)}
- {nftName}
+ {getName()}
-
);
}
export default Nft;
diff --git a/src/app/screens/nftDashboard/nftImage.tsx b/src/app/screens/nftDashboard/nftImage.tsx
index a20444b5d..c6080b124 100644
--- a/src/app/screens/nftDashboard/nftImage.tsx
+++ b/src/app/screens/nftDashboard/nftImage.tsx
@@ -1,10 +1,10 @@
import { Suspense } from 'react';
import styled from 'styled-components';
import { Ring } from 'react-spinners-css';
+import Img from 'react-image';
import { TokenMetaData } from '@secretkeylabs/xverse-core/types/api/stacks/assets';
import { getFetchableUrl } from '@utils/helper';
import NftPlaceholderImage from '@assets/img/nftDashboard/ic_nft_diamond.svg';
-import Img from 'react-image';
const ImageContainer = styled.div((props) => ({
padding: props.theme.spacing(10),
@@ -22,12 +22,6 @@ interface Props {
metadata: TokenMetaData;
}
-const showloader = (
-
-
-
-);
-
const showNftImagePlaceholder = (
@@ -38,21 +32,30 @@ function NftImage({ metadata }: Props) {
if (metadata?.image_protocol) {
return (
-
+
+
+
+ )}
+ unloader={showNftImagePlaceholder}
+ />
);
}
if (metadata?.asset_protocol) {
return (
-
-
-
+
);
}
return (
- showloader
+
+
+
);
}
diff --git a/src/app/screens/nftDetail/descriptionTile.tsx b/src/app/screens/nftDetail/descriptionTile.tsx
new file mode 100644
index 000000000..6b8f98fea
--- /dev/null
+++ b/src/app/screens/nftDetail/descriptionTile.tsx
@@ -0,0 +1,36 @@
+import styled from 'styled-components';
+
+const DescriptionHeadingText = styled.h1((props) => ({
+ ...props.theme.headline_category_s,
+ color: props.theme.colors.white['400'],
+ marginBottom: props.theme.spacing(2),
+ letterSpacing: '0.02em',
+ textTransform: 'uppercase',
+}));
+
+const DescriptionValueText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ color: props.theme.colors.white['0'],
+ marginBottom: props.theme.spacing(21),
+}));
+
+const ColumnContainer = styled.h1({
+ display: 'flex',
+ flexDirection: 'column',
+});
+
+interface Props {
+ title: string,
+ value: string
+}
+
+function DescriptionTile({ title, value }: Props) {
+ return (
+
+ {title}
+ {value}
+
+ );
+}
+
+export default DescriptionTile;
diff --git a/src/app/screens/nftDetail/index.tsx b/src/app/screens/nftDetail/index.tsx
new file mode 100644
index 000000000..55557f837
--- /dev/null
+++ b/src/app/screens/nftDetail/index.tsx
@@ -0,0 +1,339 @@
+import styled, { useTheme } from 'styled-components';
+import { useTranslation } from 'react-i18next';
+import { useNavigate, useParams } from 'react-router-dom';
+import NftImage from '@screens/nftDashboard/nftImage';
+import ArrowSquareOut from '@assets/img/send/arrow_square_out.svg';
+import TopRow from '@components/topRow';
+import BottomTabBar from '@components/tabBar';
+import SquaresFour from '@assets/img/nftDashboard/squares_four.svg';
+import ArrowUpRight from '@assets/img/dashboard/arrow_up_right.svg';
+import ShareNetwork from '@assets/img/nftDashboard/share_network.svg';
+import ActionButton from '@components/button';
+import useWalletSelector from '@hooks/useWalletSelector';
+import { useEffect, useState } from 'react';
+import ShareDialog from '@components/shareNft';
+import { GAMMA_URL } from '@utils/constants';
+import { getExplorerUrl } from '@utils/helper';
+import useNftDataSelector from '@hooks/useNftDataSelector';
+import useNftDataReducer from '@hooks/useNftReducer';
+import { useMutation } from '@tanstack/react-query';
+import { getNftDetail } from '@secretkeylabs/xverse-core/api';
+import { NftData } from '@secretkeylabs/xverse-core/types/api/stacks/assets';
+import { NftDetailResponse } from '@secretkeylabs/xverse-core/types';
+import { Ring } from 'react-spinners-css';
+import NftAttribute from './nftAttribute';
+import DescriptionTile from './descriptionTile';
+
+const Container = styled.div`
+display: flex;
+flex-direction: column;
+flex: 1;
+overflow-y: auto;
+margin-left: 5%;
+margin-right: 5%;
+&::-webkit-scrollbar {
+ display: none;
+}`;
+
+const ButtonContainer = styled.div((props) => ({
+ display: 'flex',
+ position: 'relative',
+ flexDirection: 'row',
+ maxWidth: 400,
+ marginBottom: props.theme.spacing(12),
+}));
+
+const ExtensionContainer = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ flex: 1,
+});
+
+const NFtContainer = styled.div((props) => ({
+ maxWidth: 450,
+ width: '60%',
+ display: 'flex',
+ aspectRatio: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: 8,
+ padding: props.theme.spacing(5),
+ marginTop: props.theme.spacing(15),
+ marginBottom: props.theme.spacing(12),
+}));
+
+const NftTitleText = styled.h1((props) => ({
+ ...props.theme.headline_s,
+ color: props.theme.colors.white['0'],
+ textAlign: 'center',
+}));
+
+const NftGalleryTitleText = styled.h1((props) => ({
+ ...props.theme.headline_l,
+ color: props.theme.colors.white['0'],
+ marginBottom: props.theme.spacing(12),
+}));
+
+const DescriptionText = styled.h1((props) => ({
+ ...props.theme.headline_m,
+ color: props.theme.colors.white['0'],
+ marginBottom: props.theme.spacing(12),
+}));
+
+const NftOwnedByText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ color: props.theme.colors.white['400'],
+ textAlign: 'center',
+}));
+
+const OwnerAddressText = styled.h1((props) => ({
+ ...props.theme.body_medium_m,
+ textAlign: 'center',
+ marginLeft: props.theme.spacing(3),
+}));
+
+const BottomBarContainer = styled.div({
+ marginTop: 'auto',
+});
+
+const RowContainer = styled.h1((props) => ({
+ display: 'flex',
+ marginTop: props.theme.spacing(3),
+ flexDirection: 'row',
+}));
+
+const GridContainer = styled.div((props) => ({
+ display: 'grid',
+ marginTop: props.theme.spacing(6),
+ columnGap: props.theme.spacing(8),
+ rowGap: props.theme.spacing(6),
+ gridTemplateColumns: 'repeat(auto-fit,minmax(150px,1fr))',
+ paddingBottom: props.theme.spacing(20),
+ marginBottom: props.theme.spacing(12),
+ borderBottom: `1px solid ${props.theme.colors.white['400']}`,
+}));
+
+const DescriptionContainer = styled.h1((props) => ({
+ display: 'flex',
+ marginLeft: props.theme.spacing(20),
+ marginTop: props.theme.spacing(15),
+ flexDirection: 'column',
+}));
+
+const AttributeText = styled.h1((props) => ({
+ ...props.theme.headline_category_s,
+ color: props.theme.colors.white['400'],
+ marginBottom: props.theme.spacing(2),
+ letterSpacing: '0.02em',
+ textTransform: 'uppercase',
+}));
+
+const Button = styled.button((props) => ({
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ background: 'transparent',
+ marginBottom: props.theme.spacing(12),
+}));
+
+const ButtonText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ color: props.theme.colors.white['400'],
+}));
+
+const ButtonHiglightedText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ color: props.theme.colors.white['0'],
+ marginLeft: props.theme.spacing(2),
+ marginRight: props.theme.spacing(2),
+}));
+
+const LoaderContainer = styled.div({
+ display: 'flex',
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+});
+
+function NftDetailScreen() {
+ const { t } = useTranslation('translation', { keyPrefix: 'NFT_DETAIL_SCREEN' });
+ const navigate = useNavigate();
+ const { stxAddress } = useWalletSelector();
+ const theme = useTheme();
+ const { id } = useParams();
+ const nftIdDetails = id!.split('::');
+ const { nftData } = useNftDataSelector();
+ const { storeNftData } = useNftDataReducer();
+ const [nft, setNft] = useState(undefined);
+
+ const {
+ isLoading,
+ data: nftDetailsData,
+ mutate,
+ } = useMutation<
+ NftDetailResponse | undefined,
+ Error,
+ { principal: string }>(async ({ principal }) => {
+ const contractInfo: string[] = principal.split('.');
+ return getNftDetail(
+ nftIdDetails[2].replace('u', ''),
+ contractInfo[0],
+ contractInfo[1],
+ );
+ });
+
+ const [showShareNftOptions, setShowNftOptions] = useState(false);
+ const isGalleryOpen: boolean = document.documentElement.clientWidth > 360;
+
+ useEffect(() => {
+ const data = nftData.find((nftItem) => nftItem?.asset_id === nftIdDetails[1]);
+ if (!data) {
+ mutate({ principal: nftIdDetails[0] });
+ } else {
+ setNft(data);
+ }
+ }, []);
+
+ useEffect(() => {
+ if (nftDetailsData) {
+ storeNftData(nftDetailsData);
+ setNft(nftDetailsData?.data);
+ }
+ }, [nftDetailsData]);
+
+ const handleBackButtonClick = () => {
+ navigate('/nft-dashboard');
+ };
+
+ const onSharePress = () => {
+ setShowNftOptions(true);
+ };
+
+ const onCrossPress = () => {
+ setShowNftOptions(false);
+ };
+
+ const onGammaPress = () => {
+ window.open(`${GAMMA_URL}collections/${nft?.token_metadata?.contract_id}`);
+ };
+
+ const onExplorerPress = () => {
+ const address = nft?.token_metadata?.contract_id?.split('.')!;
+ window.open(getExplorerUrl(address[0]));
+ };
+
+ const openInGalleryView = async () => {
+ await chrome.tabs.create({
+ url: chrome.runtime.getURL(`options.html#/nft-dashboard/nft-detail/${id}`),
+ });
+ };
+
+ const nftImage = (
+
+
+
+ );
+
+ const ownedByView = (
+
+ {t('OWNED_BY')}
+
+ {`${stxAddress.substring(0, 4)}...${stxAddress.substring(
+ stxAddress.length - 4,
+ stxAddress.length,
+ )}`}
+
+
+ );
+
+ const buttons = (
+
+
+
+ {showShareNftOptions && }
+
+ );
+
+ const extensionView = (
+ <>
+
+ {nftImage}
+ {nft?.token_metadata.name}
+ {ownedByView}
+
+
+ {buttons}
+ >
+ );
+
+ const galleryView = (
+ isLoading || !nft ? (
+
+
+
+ ) : (
+
+ {nft?.token_metadata.name}
+ {buttons}
+
+ {nftImage}
+
+
+ {t('DESCRIPTION')}
+
+
+ {nft?.rarity_score && }
+
+ {nft?.nft_token_attributes.length !== 0 && (
+ <>
+ {t('ATTRIBUTES')}
+
+ {nft?.nft_token_attributes.map((attribute) => ())}
+
+ >
+ )}
+
+
+
+
+
+ )
+
+ );
+
+ return (
+ <>
+
+
+ {isGalleryOpen ? galleryView : extensionView}
+
+
+
+
+
+ >
+
+ );
+}
+
+export default NftDetailScreen;
diff --git a/src/app/screens/nftDetail/nftAttribute.tsx b/src/app/screens/nftDetail/nftAttribute.tsx
new file mode 100644
index 000000000..3e25a76ef
--- /dev/null
+++ b/src/app/screens/nftDetail/nftAttribute.tsx
@@ -0,0 +1,38 @@
+import styled from 'styled-components';
+
+const Container = styled.h1((props) => ({
+ display: 'flex',
+ borderRadius: 20,
+ border: `1px solid ${props.theme.colors.background.elevation3}`,
+ flexDirection: 'row',
+ marginEnd: 10,
+ padding: props.theme.spacing(5),
+ alignItems: 'center',
+}));
+
+const TypeText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ color: props.theme.colors.white['400'],
+}));
+
+const ValueText = styled.h1((props) => ({
+ ...props.theme.body_medium_m,
+ color: props.theme.colors.white['0'],
+ marginLeft: props.theme.spacing(3),
+}));
+
+interface Props {
+ type: string;
+ value: string;
+}
+
+function NftAttribute({ type, value }: Props) {
+ return (
+
+ {type}
+ {value}
+
+ );
+}
+
+export default NftAttribute;
diff --git a/src/app/stores/index.ts b/src/app/stores/index.ts
index 8b2fc958a..2ac39040b 100644
--- a/src/app/stores/index.ts
+++ b/src/app/stores/index.ts
@@ -4,16 +4,19 @@ import { persistReducer, persistStore } from 'redux-persist';
import createSagaMiddleware from 'redux-saga';
import walletReducer from './wallet/walletReducer';
import rootSaga from './root/saga';
+import NftDataStateReducer from './nftData/reducer';
export const storage = new ChromeStorage(chrome.storage.local, chrome.runtime);
const rootPersistConfig = {
key: 'root',
storage,
+ blacklist: ['nftDataState'],
};
const appReducer = combineReducers({
walletState: walletReducer,
+ nftDataState: NftDataStateReducer,
});
const rootReducer = (state: any, action: any) => appReducer(state, action);
diff --git a/src/app/stores/nftData/actions/actionCreator.ts b/src/app/stores/nftData/actions/actionCreator.ts
new file mode 100644
index 000000000..983f2ca6e
--- /dev/null
+++ b/src/app/stores/nftData/actions/actionCreator.ts
@@ -0,0 +1,10 @@
+/* eslint-disable import/prefer-default-export */
+import { NftData } from '@secretkeylabs/xverse-core/types/api/stacks/assets';
+import * as actions from './types';
+
+export function setNftDataAction(nftData: NftData[]): actions.SetNftData {
+ return {
+ type: actions.SetNftDataKey,
+ nftData,
+ };
+}
diff --git a/src/app/stores/nftData/actions/types.ts b/src/app/stores/nftData/actions/types.ts
new file mode 100644
index 000000000..0820c66f6
--- /dev/null
+++ b/src/app/stores/nftData/actions/types.ts
@@ -0,0 +1,14 @@
+import { NftData } from '@secretkeylabs/xverse-core/types/api/stacks/assets';
+
+export interface NftDataState {
+ nftData: NftData[];
+}
+
+export const SetNftDataKey = 'SetNftData';
+
+export interface SetNftData {
+ type: typeof SetNftDataKey;
+ nftData: NftData[];
+}
+
+export type NftDataAction = SetNftData;
diff --git a/src/app/stores/nftData/reducer.ts b/src/app/stores/nftData/reducer.ts
new file mode 100644
index 000000000..2639076ec
--- /dev/null
+++ b/src/app/stores/nftData/reducer.ts
@@ -0,0 +1,23 @@
+import { NftDataAction, NftDataState, SetNftDataKey } from './actions/types';
+
+const initialNftDataState :NftDataState = {
+ nftData: [],
+};
+
+const NftDataStateReducer = (
+ // eslint-disable-next-line @typescript-eslint/default-param-last
+ state: NftDataState = initialNftDataState,
+ action: NftDataAction,
+): NftDataState => {
+ switch (action.type) {
+ case SetNftDataKey:
+ return {
+ ...state,
+ nftData: action.nftData,
+ };
+ default:
+ return state;
+ }
+};
+
+export default NftDataStateReducer;
diff --git a/src/locales/en.json b/src/locales/en.json
index 9f18cf98f..4f64fc6c9 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -180,6 +180,25 @@
"COPY": "Copy link",
"NFT_DETAIL":"Item detail"
},
+ "NFT_DETAIL_SCREEN": {
+ "NFT_DETAIL":"Item detail",
+ "WEB_GALLERY": "Open web gallery",
+ "SEND": "Send",
+ "SHARE": "Share",
+ "OWNED_BY": "Owned By",
+ "DESCRIPTION": "Description",
+ "NAME": "Name",
+ "CREATOR": "Creator",
+ "LAST_SOLD": "Last sold",
+ "STATUS": "Status",
+ "RARITY": "Overall rarity",
+ "CONTRACT_ID": "Contract ID",
+ "ATTRIBUTES": "Attributes",
+ "VIEW_CONTRACT": "View the contract on",
+ "STACKS_EXPLORER":"Stacks Explorer",
+ "DETAILS": "See detail on",
+ "GAMMA": "Gamma.io"
+ },
"RESET_WALLET_SCREEN": {
"ENTER_PASSWORD": "Enter your password to reset your wallet",
"PASSWORD": "Password",
From 0410a00c0b803121bc35b6f10126a746a14c441e Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Thu, 10 Nov 2022 16:39:02 +0500
Subject: [PATCH 02/10] Add NFT send functionality
---
.../components/recipinetAddressView/index.tsx | 6 +-
src/app/components/sendForm/index.tsx | 41 +++--
src/app/components/shareNft/index.tsx | 3 -
src/app/components/topRow/index.tsx | 4 +-
src/app/hooks/useBnsName.ts | 62 +++++++
src/app/routes/index.tsx | 10 +
.../screens/confirmNftTransaction/index.tsx | 154 ++++++++++++++++
.../confirmStxTransactionComponent/index.tsx | 4 +-
src/app/screens/nftDashboard/index.tsx | 13 +-
src/app/screens/nftDetail/index.tsx | 24 ++-
src/app/screens/sendNft/index.tsx | 173 ++++++++++++++++++
src/app/screens/sendStx/index.tsx | 2 +-
src/app/utils/helper.ts | 21 +++
src/locales/en.json | 7 +-
14 files changed, 496 insertions(+), 28 deletions(-)
create mode 100644 src/app/hooks/useBnsName.ts
create mode 100644 src/app/screens/confirmNftTransaction/index.tsx
create mode 100644 src/app/screens/sendNft/index.tsx
diff --git a/src/app/components/recipinetAddressView/index.tsx b/src/app/components/recipinetAddressView/index.tsx
index 7d897e183..600d8b575 100644
--- a/src/app/components/recipinetAddressView/index.tsx
+++ b/src/app/components/recipinetAddressView/index.tsx
@@ -2,6 +2,8 @@ import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import ArrowSquareOut from '@assets/img/send/arrow_square_out.svg';
import { getExplorerUrl } from '@utils/helper';
+import { useBnsName } from '@hooks/useBnsName';
+import useWalletSelector from '@hooks/useWalletSelector';
const InfoContainer = styled.div((props) => ({
display: 'flex',
@@ -47,8 +49,9 @@ interface Props {
recipient: string;
}
function RecipientAddressView({ recipient }: Props) {
+ const { network } = useWalletSelector();
const { t } = useTranslation('translation', { keyPrefix: 'CONFIRM_TRANSACTION' });
-
+ const bnsName = useBnsName(recipient, network);
const handleOnPress = () => {
window.open(getExplorerUrl(recipient));
};
@@ -56,6 +59,7 @@ function RecipientAddressView({ recipient }: Props) {
return (
{t('RECEPIENT_ADDRESS')}
+ {bnsName}
{recipient}
diff --git a/src/app/components/sendForm/index.tsx b/src/app/components/sendForm/index.tsx
index d94ce3090..3034eae15 100644
--- a/src/app/components/sendForm/index.tsx
+++ b/src/app/components/sendForm/index.tsx
@@ -14,6 +14,7 @@ import ActionButton from '@components/button';
import {
btcToSats, getBtcFiatEquivalent, getStxFiatEquivalent, stxToMicrostacks,
} from '@secretkeylabs/xverse-core/currency';
+import { useBNSResolver, useDebounce } from '@hooks/useBnsName';
const ScrollContainer = styled.div`
display: flex;
@@ -23,6 +24,8 @@ const ScrollContainer = styled.div`
&::-webkit-scrollbar {
display: none;
}
+ margin-left: 5%;
+ margin-right: 5%;
`;
const OuterContainer = styled.div({
display: 'flex',
@@ -39,8 +42,6 @@ const RowContainer = styled.div({
const InfoContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'row',
- marginLeft: props.theme.spacing(8),
- marginRight: props.theme.spacing(8),
padding: props.theme.spacing(8),
border: `1px solid ${props.theme.colors.background.elevation3}`,
borderRadius: 8,
@@ -50,14 +51,10 @@ const Container = styled.div((props) => ({
display: 'flex',
flexDirection: 'column',
marginTop: props.theme.spacing(11),
- marginLeft: props.theme.spacing(8),
- marginRight: props.theme.spacing(8),
}));
const ErrorContainer = styled.div((props) => ({
marginTop: props.theme.spacing(8),
- marginLeft: props.theme.spacing(10),
- marginRight: props.theme.spacing(10),
}));
const ErrorText = styled.h1((props) => ({
@@ -94,6 +91,11 @@ const SubText = styled.h1((props) => ({
color: props.theme.colors.white['400'],
}));
+const AssociatedText = styled.h1((props) => ({
+ ...props.theme.body_xs,
+ wordWrap: 'break-word',
+}));
+
const BalanceText = styled.h1((props) => ({
...props.theme.body_medium_m,
color: props.theme.colors.white['400'],
@@ -131,8 +133,6 @@ const TickerImage = styled.img((props) => ({
}));
const SendButtonContainer = styled.div((props) => ({
- paddingLeft: props.theme.spacing(8),
- paddingRight: props.theme.spacing(8),
paddingBottom: props.theme.spacing(8),
paddingTop: props.theme.spacing(4),
}));
@@ -164,10 +164,17 @@ function SendForm({
const [memo, setMemo] = useState('');
const [fiatAmount, setFiatAmount] = useState('0');
const [recipientAddress, setRecipientAddress] = useState('');
-
- const { stxBtcRate, btcFiatRate, fiatCurrency } = useSelector(
+ const {
+ stxBtcRate, btcFiatRate, fiatCurrency, stxAddress,
+ } = useSelector(
(state: StoreState) => state.walletState,
);
+ const debouncedSearchTerm = useDebounce(recipientAddress, 300);
+ const associatedAddress = useBNSResolver(
+ debouncedSearchTerm,
+ stxAddress,
+ currencyType,
+ );
function getFiatEquivalent(value: number) {
if ((currencyType === 'FT' && !fungibleToken?.tokenFiatRate) || currencyType === 'NFT') {
@@ -262,6 +269,10 @@ function SendForm({
);
}
+ const onAddressInputChange = (e: { target: { value: SetStateAction } }) => {
+ setRecipientAddress(e.target.value);
+ };
+
function renderEnterRecepientSection() {
return (
@@ -270,16 +281,22 @@ function SendForm({
} }) => setRecipientAddress(e.target.value)}
+ onChange={onAddressInputChange}
/>
+ {associatedAddress && (
+ <>
+ {t('ASSOCIATED_ADDRESS')}
+ {associatedAddress}
+ >
+ )}
);
}
const handleOnPress = () => {
- onPressSend(recipientAddress, amount, memo);
+ onPressSend(associatedAddress !== '' ? associatedAddress : recipientAddress, amount, memo);
};
return (
diff --git a/src/app/components/shareNft/index.tsx b/src/app/components/shareNft/index.tsx
index 8adad553c..d9389a985 100644
--- a/src/app/components/shareNft/index.tsx
+++ b/src/app/components/shareNft/index.tsx
@@ -13,9 +13,6 @@ import ShareLinkRow from './shareLinkRow';
const Container = styled.button((props) => ({
display: 'flex',
flexDirection: 'column',
- position: 'absolute',
- top: 0,
- right: 0,
justifyContent: 'center',
paddingLeft: props.theme.spacing(6),
paddingRight: props.theme.spacing(8),
diff --git a/src/app/components/topRow/index.tsx b/src/app/components/topRow/index.tsx
index de6c08909..7f6ba2c09 100644
--- a/src/app/components/topRow/index.tsx
+++ b/src/app/components/topRow/index.tsx
@@ -27,8 +27,8 @@ const RowContainer = styled.div((props) => ({
flexDirection: 'row',
alignItems: 'center',
paddingTop: props.theme.spacing(11),
- paddingLeft: props.theme.spacing(11),
- paddingRight: props.theme.spacing(11),
+ paddingLeft: '5%',
+ paddingRight: '5%',
}));
interface Props {
diff --git a/src/app/hooks/useBnsName.ts b/src/app/hooks/useBnsName.ts
new file mode 100644
index 000000000..53f80ce59
--- /dev/null
+++ b/src/app/hooks/useBnsName.ts
@@ -0,0 +1,62 @@
+import { useEffect, useState } from 'react';
+import { SettingsNetwork, validateStxAddress } from '@secretkeylabs/xverse-core';
+import {
+ fetchAddressOfBnsName, getBnsName,
+} from '@secretkeylabs/xverse-core/api';
+import useWalletSelector from './useWalletSelector';
+
+export const useBnsName = (walletAddress: string, network: SettingsNetwork) => {
+ const [bnsName, setBnsName] = useState('');
+
+ useEffect(() => {
+ (async () => {
+ const name = await getBnsName(walletAddress, network);
+ setBnsName(name ?? '');
+ })();
+ }, [walletAddress]);
+
+ return bnsName;
+};
+
+export const useBNSResolver = (
+ recipientAddress: string,
+ walletAddress: string,
+ currencyType: string,
+) => {
+ const { network } = useWalletSelector();
+ const [associatedAddress, setAssociatedAddress] = useState('');
+
+ useEffect(() => {
+ (async () => {
+ if (currencyType !== 'BTC') {
+ if (!validateStxAddress({ stxAddress: recipientAddress, network })) {
+ const address = await fetchAddressOfBnsName(
+ recipientAddress.toLocaleLowerCase(),
+ walletAddress.toLocaleLowerCase(),
+ network,
+ );
+ setAssociatedAddress(address ?? '');
+ } else {
+ setAssociatedAddress('');
+ }
+ } else {
+ setAssociatedAddress(recipientAddress);
+ }
+ })();
+ }, [recipientAddress]);
+
+ return associatedAddress;
+};
+
+export function useDebounce(value: string, delay: number) {
+ const [debouncedValue, setDebouncedValue] = useState(value);
+ useEffect(() => {
+ const handler = setTimeout(() => {
+ setDebouncedValue(value);
+ }, delay);
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [value, delay]);
+ return debouncedValue;
+}
diff --git a/src/app/routes/index.tsx b/src/app/routes/index.tsx
index f9c057e73..658f0078f 100644
--- a/src/app/routes/index.tsx
+++ b/src/app/routes/index.tsx
@@ -22,6 +22,8 @@ import ForgotPassword from '@screens/forgotPassword';
import BackupWalletSteps from '@screens/backupWalletSteps';
import NftDashboard from '@screens/nftDashboard';
import NftDetailScreen from '@screens/nftDetail';
+import SendNft from '@screens/sendNft';
+import ConfirmNftTransaction from '@screens/confirmNftTransaction';
const router = createHashRouter([
{
@@ -68,6 +70,10 @@ const router = createHashRouter([
path: 'send-btc',
element: ,
},
+ {
+ path: 'nft-dashboard/nft-detail/:id/send-nft',
+ element: ,
+ },
{
path: 'confirm-stx-tx',
element: ,
@@ -116,6 +122,10 @@ const router = createHashRouter([
path: 'nft-dashboard/nft-detail/:id',
element: ,
},
+ {
+ path: 'confirm-nft-tx/:id',
+ element: ,
+ },
],
},
]);
diff --git a/src/app/screens/confirmNftTransaction/index.tsx b/src/app/screens/confirmNftTransaction/index.tsx
new file mode 100644
index 000000000..0cf5e9ac4
--- /dev/null
+++ b/src/app/screens/confirmNftTransaction/index.tsx
@@ -0,0 +1,154 @@
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+import { useMutation } from '@tanstack/react-query';
+import { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { useLocation, useNavigate, useParams } from 'react-router-dom';
+import { StacksTransaction } from '@secretkeylabs/xverse-core/types';
+import { broadcastSignedTransaction } from '@secretkeylabs/xverse-core/transactions';
+import Seperator from '@components/seperator';
+import { StoreState } from '@stores/index';
+import BottomBar from '@components/tabBar';
+import { fetchStxWalletDataRequestAction } from '@stores/wallet/actions/actionCreators';
+import RecipientAddressView from '@components/recipinetAddressView';
+import ConfirmStxTransationComponent from '@screens/confirmStxTransaxtion/confirmStxTransactionComponent';
+import useNftDataSelector from '@hooks/useNftDataSelector';
+import NftImage from '@screens/nftDashboard/nftImage';
+
+const InfoContainer = styled.div((props) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ marginTop: props.theme.spacing(12),
+}));
+
+const TitleText = styled.h1((props) => ({
+ ...props.theme.headline_category_s,
+ color: props.theme.colors.white['400'],
+ textTransform: 'uppercase',
+}));
+
+const ValueText = styled.h1((props) => ({
+ ...props.theme.body_m,
+ marginTop: props.theme.spacing(2),
+ wordBreak: 'break-all',
+}));
+
+const Container = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+});
+
+const NFtContainer = styled.div((props) => ({
+ maxWidth: 450,
+ width: '60%',
+ display: 'flex',
+ aspectRatio: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: 8,
+ padding: props.theme.spacing(5),
+ marginBottom: props.theme.spacing(6),
+}));
+
+const NftTitleText = styled.h1((props) => ({
+ ...props.theme.headline_s,
+ color: props.theme.colors.white['0'],
+ textAlign: 'center',
+}));
+
+function ConfirmNftTransaction() {
+ const { t } = useTranslation('translation', { keyPrefix: 'CONFIRM_TRANSACTION' });
+ const navigate = useNavigate();
+ const dispatch = useDispatch();
+ const location = useLocation();
+ const { id } = useParams();
+ const { nftData } = useNftDataSelector();
+ const nftIdDetails = id!.split('::');
+ const nft = nftData.find((nftItem) => nftItem?.asset_id === nftIdDetails[1]);
+ const { unsignedTx, recipientAddress } = location.state;
+ const {
+ stxBtcRate, network, stxAddress, fiatCurrency,
+ } = useSelector(
+ (state: StoreState) => state.walletState,
+ );
+
+ const {
+ isLoading,
+ error: txError,
+ data: stxTxBroadcastData,
+ mutate,
+ } = useMutation<
+ string,
+ Error,
+ { signedTx: StacksTransaction }>(async ({ signedTx }) => broadcastSignedTransaction(signedTx, network));
+
+ useEffect(() => {
+ if (stxTxBroadcastData) {
+ navigate('/tx-status', {
+ state: {
+ txid: stxTxBroadcastData,
+ currency: 'STX',
+ error: '',
+ },
+ });
+ setTimeout(() => {
+ dispatch(fetchStxWalletDataRequestAction(stxAddress, network, fiatCurrency, stxBtcRate));
+ }, 1000);
+ }
+ }, [stxTxBroadcastData]);
+
+ useEffect(() => {
+ if (txError) {
+ navigate('/tx-status', {
+ state: {
+ txid: '',
+ currency: 'STX',
+ error: txError.toString(),
+ },
+ });
+ }
+ }, [txError]);
+
+ const networkInfoSection = (
+
+ {t('NETWORK')}
+ {network.type}
+
+ );
+
+ const handleOnConfirmClick = (txs: StacksTransaction[]) => {
+ mutate({ signedTx: txs[0] });
+ };
+
+ const handleOnCancelClick = () => {
+ navigate(-1);
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {nft?.token_metadata.name}
+
+
+ {networkInfoSection}
+
+
+
+ >
+ );
+}
+export default ConfirmNftTransaction;
diff --git a/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx b/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx
index a676bd59b..1f3acf4cf 100644
--- a/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx
+++ b/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx
@@ -48,6 +48,7 @@ interface Props {
onConfirmClick: (transactions: StacksTransaction[]) => void;
children: ReactNode;
isSponsored?: boolean;
+ isNft?: boolean;
}
function ConfirmStxTransationComponent({
@@ -57,6 +58,7 @@ function ConfirmStxTransationComponent({
children,
onConfirmClick,
onCancelClick,
+ isNft,
}: Props) {
const { t } = useTranslation('translation', { keyPrefix: 'CONFIRM_TRANSACTION' });
const {
@@ -148,7 +150,7 @@ function ConfirmStxTransationComponent({
<>
-
+ {!isNft && }
{children}
({
...props.theme.headline_category_s,
color: props.theme.colors.white['200'],
@@ -105,7 +111,7 @@ function NftDashboard() {
const { isLoading, data } = useQuery(
['nft-meta-data', { stxAddress, network, offset: offset.current }],
- async () => getNftsData('SP2VC4CXTWYRZEV7MSGXPNHE739N14ECQWX8JP2BF', network, offset.current),
+ async () => getNftsData(stxAddress, network, offset.current),
);
useEffect(() => {
@@ -181,7 +187,10 @@ function NftDashboard() {
buttonBorderColor={theme.colors.background.elevation2}
/>
{showShareNftOptions && (
-
+
+
+
+
)}
{isLoading ? (
diff --git a/src/app/screens/nftDetail/index.tsx b/src/app/screens/nftDetail/index.tsx
index 55557f837..979c13df0 100644
--- a/src/app/screens/nftDetail/index.tsx
+++ b/src/app/screens/nftDetail/index.tsx
@@ -51,13 +51,19 @@ const ExtensionContainer = styled.div({
flex: 1,
});
+const ShareDialogeContainerContainer = styled.div({
+ position: 'absolute',
+ bottom: 0,
+ right: 0,
+});
+
const NFtContainer = styled.div((props) => ({
maxWidth: 450,
width: '60%',
display: 'flex',
aspectRatio: 1,
justifyContent: 'center',
- alignItems: 'center',
+ alignItems: 'flex-start',
borderRadius: 8,
padding: props.theme.spacing(5),
marginTop: props.theme.spacing(15),
@@ -251,9 +257,17 @@ function NftDetailScreen() {
);
+ const handleOnSendClick = () => {
+ navigate('send-nft', {
+ state: {
+ nft,
+ },
+ });
+ };
+
const buttons = (
-
+
- {showShareNftOptions && }
+
+ {showShareNftOptions && }
+
+
);
@@ -327,7 +344,6 @@ function NftDetailScreen() {
{isGalleryOpen ? galleryView : extensionView}
-
diff --git a/src/app/screens/sendNft/index.tsx b/src/app/screens/sendNft/index.tsx
new file mode 100644
index 000000000..aec3e58e7
--- /dev/null
+++ b/src/app/screens/sendNft/index.tsx
@@ -0,0 +1,173 @@
+import { useTranslation } from 'react-i18next';
+import { useEffect, useState } from 'react';
+import styled from 'styled-components';
+import { useNavigate, useParams } from 'react-router-dom';
+import { StacksTransaction, cvToHex, uintCV } from '@secretkeylabs/xverse-core/types';
+import { useMutation } from '@tanstack/react-query';
+import { generateUnsignedTransaction } from '@secretkeylabs/xverse-core/api';
+import { validateStxAddress } from '@secretkeylabs/xverse-core';
+import SendForm from '@components/sendForm';
+import useStxPendingTxData from '@hooks/useStxPendingTxData';
+import useWalletSelector from '@hooks/useWalletSelector';
+import TopRow from '@components/topRow';
+import BottomBar from '@components/tabBar';
+import { checkNftExists } from '@utils/helper';
+import NftImage from '@screens/nftDashboard/nftImage';
+import useNftDataSelector from '@hooks/useNftDataSelector';
+
+const OuterContainer = styled.div`
+display: flex;
+flex-direction: column;
+flex: 1;
+overflow-y: auto;
+&::-webkit-scrollbar {
+ display: none;
+}`;
+
+const Container = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ flex: 1,
+});
+
+const NFtContainer = styled.div((props) => ({
+ maxWidth: 450,
+ width: '60%',
+ display: 'flex',
+ aspectRatio: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: 8,
+ padding: props.theme.spacing(5),
+ marginTop: props.theme.spacing(15),
+ marginBottom: props.theme.spacing(6),
+}));
+
+const NftTitleText = styled.h1((props) => ({
+ ...props.theme.headline_s,
+ color: props.theme.colors.white['0'],
+ textAlign: 'center',
+}));
+
+function SendNft() {
+ const { t } = useTranslation('translation', { keyPrefix: 'SEND' });
+ const navigate = useNavigate();
+ const { id } = useParams();
+ const { nftData } = useNftDataSelector();
+ const nftIdDetails = id!.split('::');
+ const nft = nftData.find((nftItem) => nftItem?.asset_id === nftIdDetails[1]);
+ const { data: stxPendingTxData } = useStxPendingTxData();
+ const {
+ stxAddress,
+ stxPublicKey,
+ network,
+ feeMultipliers,
+ } = useWalletSelector();
+ const [error, setError] = useState('');
+ const [recipientAddress, setRecipientAddress] = useState('');
+ const { isLoading, data, mutate } = useMutation<
+ StacksTransaction,
+ Error,
+ { tokenId: string; associatedAddress: string }
+ >(async ({ tokenId, associatedAddress }) => {
+ const principal = nft?.fully_qualified_token_id?.split('::')!;
+ const name = principal[1].split(':')[0];
+ const contractInfo: string[] = principal[0].split('.');
+ const unsignedTx: StacksTransaction = await generateUnsignedTransaction(
+ tokenId,
+ stxAddress,
+ associatedAddress,
+ contractInfo[0],
+ contractInfo[1],
+ name,
+ stxPublicKey,
+ network,
+ stxPendingTxData?.pendingTransactions ?? [],
+ '',
+ true,
+ );
+ if (feeMultipliers?.stxSendTxMultiplier) {
+ unsignedTx.setFee(
+ unsignedTx.auth.spendingCondition.fee
+ * BigInt(feeMultipliers.stxSendTxMultiplier),
+ );
+ }
+ return unsignedTx;
+ });
+
+ useEffect(() => {
+ if (data) {
+ navigate(`/confirm-nft-tx/${id}`, {
+ state: {
+ unsignedTx: data,
+ recipientAddress,
+ nft,
+ },
+ });
+ }
+ }, [data]);
+
+ const handleBackButtonClick = () => {
+ navigate(-1);
+ };
+
+ function validateFields(associatedAddress: string): boolean {
+ if (!associatedAddress) {
+ setError(t('ERRORS.ADDRESS_REQUIRED'));
+ return false;
+ }
+
+ if (!validateStxAddress({ stxAddress: associatedAddress, network: network.type })) {
+ setError(t('ERRORS.ADDRESS_INVALID'));
+ return false;
+ }
+
+ if (associatedAddress === stxAddress) {
+ setError(t('ERRORS.SEND_TO_SELF'));
+ return false;
+ }
+
+ return true;
+ }
+
+ const onPressSendNFT = async (associatedAddress: string) => {
+ if (stxPendingTxData) {
+ if (checkNftExists(stxPendingTxData?.pendingTransactions, nft!)) {
+ setError(t('ERRORS.NFT_SEND_DETAIL'));
+ return;
+ }
+ }
+ setRecipientAddress(associatedAddress);
+ if (validateFields(associatedAddress.trim()) && nft) {
+ setError('');
+ const tokenId = nft?.value?.hex
+ ?? cvToHex(uintCV(nft.token_id.toString()));
+ mutate({ tokenId, associatedAddress });
+ }
+ };
+ return (
+
+
+
+
+
+
+ {nft?.token_metadata.name}
+
+
+
+
+ );
+}
+
+export default SendNft;
diff --git a/src/app/screens/sendStx/index.tsx b/src/app/screens/sendStx/index.tsx
index 5871999f6..9d0e00190 100644
--- a/src/app/screens/sendStx/index.tsx
+++ b/src/app/screens/sendStx/index.tsx
@@ -71,7 +71,7 @@ function SendStxScreen() {
setError(t('ERRORS.AMOUNT_REQUIRED'));
return false;
}
- if (!validateStxAddress({ stxAddress: associatedAddress, network })) {
+ if (!validateStxAddress({ stxAddress: associatedAddress, network: network.type })) {
setError(t('ERRORS.ADDRESS_INVALID'));
return false;
}
diff --git a/src/app/utils/helper.ts b/src/app/utils/helper.ts
index 52f6040f2..969ea71aa 100644
--- a/src/app/utils/helper.ts
+++ b/src/app/utils/helper.ts
@@ -1,3 +1,5 @@
+import { StxMempoolTransactionData } from '@secretkeylabs/xverse-core/types';
+import { NftData } from '@secretkeylabs/xverse-core/types/api/stacks/assets';
import { Account } from '@stores/wallet/actions/types';
import BigNumber from 'bignumber.js';
@@ -62,3 +64,22 @@ export function getFetchableUrl(uri: string, protocol: string): string | undefin
}
return undefined;
}
+/**
+ * check if nft transaction exists in pending transactions
+ * @param pendingTransactions
+ * @param nft
+ * @returns true if nft exists, false otherwise
+ */
+export function checkNftExists(
+ pendingTransactions: StxMempoolTransactionData[],
+ nft: NftData,
+): boolean {
+ const principal: string[] = nft?.fully_qualified_token_id?.split('::');
+ const transaction = pendingTransactions.find(
+ (tx) => tx.contractCall?.contract_id === principal[0]
+ && tx.contractCall.function_args[0].repr.substring(1)
+ === nft.token_id.toString(),
+ );
+ if (transaction) return true;
+ return false;
+}
diff --git a/src/locales/en.json b/src/locales/en.json
index 4f64fc6c9..cd3e8062b 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -49,6 +49,7 @@
"RECEPIENT_PLACEHOLDER": "Address or .btc domain",
"MEMO": "Add a memo (optional)",
"MEMO_PLACEHOLDER": "Memo",
+ "ASSOCIATED_ADDRESS": "Associated Address",
"MEMO_INFO": "Adding a memo can have an impact on the transaction fee",
"NEXT": "Next",
"ERRORS": {
@@ -61,8 +62,10 @@
"MINIMUM_AMOUNT": "Minimum amount is 0.000001 STX",
"INSUFFICIENT_BALANCE": "Insufficient balance",
"MEMO_LENGTH": "Memo exceeds allowed length",
- "INSUFFICIENT_BALANCE_FEES": "Insufficient balance when including transaction fees"
- }
+ "INSUFFICIENT_BALANCE_FEES": "Insufficient balance when including transaction fees",
+ "NFT_SEND_DETAIL": "This Nft is already sent and is in pending state"
+ },
+ "SEND_NFT":"Send NFT"
},
"CONFIRM_TRANSACTION": {
"SEND":"Send",
From d600b60200d3f7a8afbe5aff10e2d6e31fd8c059 Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Fri, 11 Nov 2022 11:37:41 +0500
Subject: [PATCH 03/10] fix hard coded address
---
src/app/screens/nftDashboard/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/screens/nftDashboard/index.tsx b/src/app/screens/nftDashboard/index.tsx
index 238f17032..944ef9a8b 100644
--- a/src/app/screens/nftDashboard/index.tsx
+++ b/src/app/screens/nftDashboard/index.tsx
@@ -105,7 +105,7 @@ function NftDashboard() {
const { isLoading, data } = useQuery(
['nft-meta-data', { stxAddress, network, offset: offset.current }],
- async () => getNftsData('SP2VC4CXTWYRZEV7MSGXPNHE739N14ECQWX8JP2BF', network, offset.current),
+ async () => getNftsData(stxAddress, network, offset.current),
);
useEffect(() => {
From c36b9282fea931dc914ea889f54ac77fdb4d18ef Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 16 Nov 2022 13:40:10 +0500
Subject: [PATCH 04/10] Fix core library imports
---
src/app/components/sendForm/index.tsx | 2 +-
.../components/transactionSetting/index.tsx | 2 +-
src/app/hooks/useStxPendingTxData.tsx | 2 +-
.../screens/confirmNftTransaction/index.tsx | 2 +-
.../screens/confirmStxTransaxtion/index.tsx | 3 +-
.../confirmBtcTransactionComponent/index.tsx | 2 +-
.../screens/confrimBtcTransaction/index.tsx | 15 +++------
src/app/screens/sendBtc/index.tsx | 4 +--
src/app/screens/sendNft/index.tsx | 32 +++++++++++--------
src/app/screens/sendStx/index.tsx | 4 +--
10 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/src/app/components/sendForm/index.tsx b/src/app/components/sendForm/index.tsx
index 3034eae15..eb662857f 100644
--- a/src/app/components/sendForm/index.tsx
+++ b/src/app/components/sendForm/index.tsx
@@ -285,7 +285,7 @@ function SendForm({
/>
- {associatedAddress && (
+ {associatedAddress && currencyType !== 'BTC' && (
<>
{t('ASSOCIATED_ADDRESS')}
{associatedAddress}
diff --git a/src/app/components/transactionSetting/index.tsx b/src/app/components/transactionSetting/index.tsx
index 5c6afef23..a2f4e53fe 100644
--- a/src/app/components/transactionSetting/index.tsx
+++ b/src/app/components/transactionSetting/index.tsx
@@ -270,7 +270,7 @@ function TransactionSettingAlert({
btcAddress,
amount?.toString()!,
selectedAccount?.id ?? 0,
- network,
+ network.type,
seedPhrase,
mode?.value,
);
diff --git a/src/app/hooks/useStxPendingTxData.tsx b/src/app/hooks/useStxPendingTxData.tsx
index 43ee2c27d..95421fd42 100644
--- a/src/app/hooks/useStxPendingTxData.tsx
+++ b/src/app/hooks/useStxPendingTxData.tsx
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
-import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/api';
+import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/transactions';
import { StoreState } from '@stores/index';
const useStxPendingTxData = () => {
diff --git a/src/app/screens/confirmNftTransaction/index.tsx b/src/app/screens/confirmNftTransaction/index.tsx
index 0cf5e9ac4..d4e8fb4f7 100644
--- a/src/app/screens/confirmNftTransaction/index.tsx
+++ b/src/app/screens/confirmNftTransaction/index.tsx
@@ -82,7 +82,7 @@ function ConfirmNftTransaction() {
} = useMutation<
string,
Error,
- { signedTx: StacksTransaction }>(async ({ signedTx }) => broadcastSignedTransaction(signedTx, network));
+ { signedTx: StacksTransaction }>(async ({ signedTx }) => broadcastSignedTransaction(signedTx, network.type));
useEffect(() => {
if (stxTxBroadcastData) {
diff --git a/src/app/screens/confirmStxTransaxtion/index.tsx b/src/app/screens/confirmStxTransaxtion/index.tsx
index a6113b0b4..b4e2a4498 100644
--- a/src/app/screens/confirmStxTransaxtion/index.tsx
+++ b/src/app/screens/confirmStxTransaxtion/index.tsx
@@ -51,7 +51,6 @@ function ConfirmStxTransaction() {
} = useSelector(
(state: StoreState) => state.walletState,
);
-
const {
isLoading,
error: txError,
@@ -60,7 +59,7 @@ function ConfirmStxTransaction() {
} = useMutation<
string,
Error,
- { signedTx: StacksTransaction }>(async ({ signedTx }) => broadcastSignedTransaction(signedTx, network));
+ { signedTx: StacksTransaction }>(async ({ signedTx }) => broadcastSignedTransaction(signedTx, network.type));
useEffect(() => {
if (stxTxBroadcastData) {
diff --git a/src/app/screens/confrimBtcTransaction/confirmBtcTransactionComponent/index.tsx b/src/app/screens/confrimBtcTransaction/confirmBtcTransactionComponent/index.tsx
index 1bcab21a5..208cea39e 100644
--- a/src/app/screens/confrimBtcTransaction/confirmBtcTransactionComponent/index.tsx
+++ b/src/app/screens/confrimBtcTransaction/confirmBtcTransactionComponent/index.tsx
@@ -84,7 +84,7 @@ function ConfirmBtcTransactionComponent({
index: selectedAccount?.id ?? 0,
fee: new BigNumber(txFee),
seedPhrase,
- network,
+ network: network.type,
}));
useEffect(() => {
diff --git a/src/app/screens/confrimBtcTransaction/index.tsx b/src/app/screens/confrimBtcTransaction/index.tsx
index 4f4ee1b4f..361faa4fa 100644
--- a/src/app/screens/confrimBtcTransaction/index.tsx
+++ b/src/app/screens/confrimBtcTransaction/index.tsx
@@ -43,14 +43,13 @@ function ConfirmBtcTransaction() {
const [recipientAddress, setRecipientAddress] = useState('');
const location = useLocation();
const { fee, amount, signedTxHex } = location.state;
-
const {
isLoading,
error: txError,
data: btcTxBroadcastData,
mutate,
} = useMutation(
- async ({ signedTx }) => broadcastRawBtcTransaction(signedTx, network),
+ async ({ signedTx }) => broadcastRawBtcTransaction(signedTx, network.type),
);
useEffect(() => {
@@ -84,13 +83,6 @@ function ConfirmBtcTransaction() {
}
}, [txError]);
- const networkInfoSection = (
-
- {t('NETWORK')}
- {network.type}
-
- );
-
const handleOnConfirmClick = (txHex: string) => {
mutate({ signedTx: txHex });
};
@@ -111,7 +103,10 @@ function ConfirmBtcTransaction() {
onBackButtonClick={goBackToScreen}
>
- {networkInfoSection}
+
+ {t('NETWORK')}
+ {network.type}
+
diff --git a/src/app/screens/sendBtc/index.tsx b/src/app/screens/sendBtc/index.tsx
index d7a01d680..49a1a6da7 100644
--- a/src/app/screens/sendBtc/index.tsx
+++ b/src/app/screens/sendBtc/index.tsx
@@ -48,7 +48,7 @@ function SendBtcScreen() {
index: selectedAccount?.id ?? 0,
fee: undefined,
seedPhrase,
- network,
+ network: network.type,
}));
const handleBackButtonClick = () => {
@@ -90,7 +90,7 @@ function SendBtcScreen() {
return false;
}
- if (!validateBtcAddress({ btcAddress: address, network })) {
+ if (!validateBtcAddress({ btcAddress: address, network: network.type })) {
setError(t('ERRORS.ADDRESS_INVALID'));
return false;
}
diff --git a/src/app/screens/sendNft/index.tsx b/src/app/screens/sendNft/index.tsx
index aec3e58e7..8a7053730 100644
--- a/src/app/screens/sendNft/index.tsx
+++ b/src/app/screens/sendNft/index.tsx
@@ -2,9 +2,11 @@ import { useTranslation } from 'react-i18next';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useNavigate, useParams } from 'react-router-dom';
-import { StacksTransaction, cvToHex, uintCV } from '@secretkeylabs/xverse-core/types';
+import {
+ StacksTransaction, cvToHex, uintCV, UnsignedStacksTransation,
+} from '@secretkeylabs/xverse-core/types';
import { useMutation } from '@tanstack/react-query';
-import { generateUnsignedTransaction } from '@secretkeylabs/xverse-core/api';
+import { generateUnsignedTransaction } from '@secretkeylabs/xverse-core/transactions';
import { validateStxAddress } from '@secretkeylabs/xverse-core';
import SendForm from '@components/sendForm';
import useStxPendingTxData from '@hooks/useStxPendingTxData';
@@ -75,18 +77,22 @@ function SendNft() {
const principal = nft?.fully_qualified_token_id?.split('::')!;
const name = principal[1].split(':')[0];
const contractInfo: string[] = principal[0].split('.');
- const unsignedTx: StacksTransaction = await generateUnsignedTransaction(
- tokenId,
- stxAddress,
- associatedAddress,
- contractInfo[0],
- contractInfo[1],
- name,
- stxPublicKey,
+ const unsginedTx: UnsignedStacksTransation = {
+ amount: tokenId,
+ senderAddress: stxAddress,
+ recipientAddress: associatedAddress,
+ contractAddress: contractInfo[0],
+ contractName: contractInfo[1],
+ assetName: name,
+ publicKey: stxPublicKey,
network,
- stxPendingTxData?.pendingTransactions ?? [],
- '',
- true,
+ pendingTxs: stxPendingTxData?.pendingTransactions ?? [],
+ memo: '',
+ isNFT: true,
+
+ };
+ const unsignedTx: StacksTransaction = await generateUnsignedTransaction(
+ unsginedTx,
);
if (feeMultipliers?.stxSendTxMultiplier) {
unsignedTx.setFee(
diff --git a/src/app/screens/sendStx/index.tsx b/src/app/screens/sendStx/index.tsx
index 9d0e00190..bc93dc978 100644
--- a/src/app/screens/sendStx/index.tsx
+++ b/src/app/screens/sendStx/index.tsx
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
-import { generateUnsignedStxTokenTransferTransaction } from '@secretkeylabs/xverse-core/api';
+import { generateUnsignedStxTokenTransferTransaction } from '@secretkeylabs/xverse-core/transactions';
import { microstacksToStx, stxToMicrostacks } from '@secretkeylabs/xverse-core/currency';
import { StacksTransaction } from '@secretkeylabs/xverse-core/types';
import { validateStxAddress } from '@secretkeylabs/xverse-core/wallet';
@@ -37,7 +37,7 @@ function SendStxScreen() {
memo!,
stxPendingTxData?.pendingTransactions ?? [],
stxPublicKey,
- network,
+ network.type,
);
// increasing the fees with multiplication factor
const fee: bigint = BigInt(unsignedSendStxTx.auth.spendingCondition.fee.toString()) ?? BigInt(0);
From fa1da3bc6fd346b8f3fd881bc66326838415b9ef Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 16 Nov 2022 15:33:15 +0500
Subject: [PATCH 05/10] fix import
---
src/app/hooks/useStxPendingTxData.tsx | 2 +-
src/app/screens/nftDashboard/index.tsx | 2 +-
src/app/screens/sendStx/index.tsx | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/app/hooks/useStxPendingTxData.tsx b/src/app/hooks/useStxPendingTxData.tsx
index 43ee2c27d..95421fd42 100644
--- a/src/app/hooks/useStxPendingTxData.tsx
+++ b/src/app/hooks/useStxPendingTxData.tsx
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
-import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/api';
+import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/transactions';
import { StoreState } from '@stores/index';
const useStxPendingTxData = () => {
diff --git a/src/app/screens/nftDashboard/index.tsx b/src/app/screens/nftDashboard/index.tsx
index 238f17032..944ef9a8b 100644
--- a/src/app/screens/nftDashboard/index.tsx
+++ b/src/app/screens/nftDashboard/index.tsx
@@ -105,7 +105,7 @@ function NftDashboard() {
const { isLoading, data } = useQuery(
['nft-meta-data', { stxAddress, network, offset: offset.current }],
- async () => getNftsData('SP2VC4CXTWYRZEV7MSGXPNHE739N14ECQWX8JP2BF', network, offset.current),
+ async () => getNftsData(stxAddress, network, offset.current),
);
useEffect(() => {
diff --git a/src/app/screens/sendStx/index.tsx b/src/app/screens/sendStx/index.tsx
index 5871999f6..ac2f474c0 100644
--- a/src/app/screens/sendStx/index.tsx
+++ b/src/app/screens/sendStx/index.tsx
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
-import { generateUnsignedStxTokenTransferTransaction } from '@secretkeylabs/xverse-core/api';
+import { generateUnsignedStxTokenTransferTransaction } from '@secretkeylabs/xverse-core/transactions';
import { microstacksToStx, stxToMicrostacks } from '@secretkeylabs/xverse-core/currency';
import { StacksTransaction } from '@secretkeylabs/xverse-core/types';
import { validateStxAddress } from '@secretkeylabs/xverse-core/wallet';
From 85dc7566948a56dc6cb6133ae98aa1172024ef4e Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 16 Nov 2022 15:52:26 +0500
Subject: [PATCH 06/10] fix core package path
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 7099d96a6..863002971 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"version": "0.0.1",
"private": true,
"dependencies": {
- "@secretkeylabs/xverse-core": "file:/Users/imamah/Desktop/xverse-core/xverse-core",
+ "@secretkeylabs/xverse-core": "github:secretkeylabs/xverse-core",
"@stacks/encryption": "4.3.5",
"@tanstack/react-query": "^4.12.0",
"@testing-library/jest-dom": "^5.16.5",
From 77583221f57e5f02b1342c0ebd3fbb1ad2daedee Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 16 Nov 2022 18:51:31 +0500
Subject: [PATCH 07/10] fix import path
---
src/app/hooks/useStxPendingTxData.tsx | 2 +-
src/app/screens/nftDetail/index.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/app/hooks/useStxPendingTxData.tsx b/src/app/hooks/useStxPendingTxData.tsx
index 95421fd42..43ee2c27d 100644
--- a/src/app/hooks/useStxPendingTxData.tsx
+++ b/src/app/hooks/useStxPendingTxData.tsx
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
-import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/transactions';
+import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/api';
import { StoreState } from '@stores/index';
const useStxPendingTxData = () => {
diff --git a/src/app/screens/nftDetail/index.tsx b/src/app/screens/nftDetail/index.tsx
index 6b594d6d2..8c5277f20 100644
--- a/src/app/screens/nftDetail/index.tsx
+++ b/src/app/screens/nftDetail/index.tsx
@@ -1,4 +1,4 @@
-import styled, { useTheme } from 'styled-components';
+import styled from 'styled-components';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'react-router-dom';
import NftImage from '@screens/nftDashboard/nftImage';
From 476ce8be1f350108ca567a7baa25e736d48870db Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Wed, 16 Nov 2022 21:39:06 +0500
Subject: [PATCH 08/10] fix import path
---
src/app/hooks/useStxPendingTxData.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/hooks/useStxPendingTxData.tsx b/src/app/hooks/useStxPendingTxData.tsx
index 95421fd42..43ee2c27d 100644
--- a/src/app/hooks/useStxPendingTxData.tsx
+++ b/src/app/hooks/useStxPendingTxData.tsx
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
-import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/transactions';
+import { fetchStxPendingTxData } from '@secretkeylabs/xverse-core/api';
import { StoreState } from '@stores/index';
const useStxPendingTxData = () => {
From f1e844f15b5ffa86abbfe0d246b2fde49bdf9839 Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Fri, 18 Nov 2022 13:29:46 +0500
Subject: [PATCH 09/10] fix ui bugs
---
.../confirmStxTransactionComponent/index.tsx | 40 +++++++++----------
src/app/components/sendForm/index.tsx | 22 ++++++++--
src/app/components/transferFeeView/index.tsx | 2 +-
.../screens/confirmNftTransaction/index.tsx | 2 +-
.../screens/confirmStxTransaxtion/index.tsx | 2 +-
src/app/screens/sendNft/index.tsx | 32 ++++++---------
6 files changed, 53 insertions(+), 47 deletions(-)
rename src/app/{screens/confirmStxTransaxtion => components}/confirmStxTransactionComponent/index.tsx (89%)
diff --git a/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx b/src/app/components/confirmStxTransactionComponent/index.tsx
similarity index 89%
rename from src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx
rename to src/app/components/confirmStxTransactionComponent/index.tsx
index b35d92890..4966b2c46 100644
--- a/src/app/screens/confirmStxTransaxtion/confirmStxTransactionComponent/index.tsx
+++ b/src/app/components/confirmStxTransactionComponent/index.tsx
@@ -35,9 +35,8 @@ const Container = styled.div`
const ButtonContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'row',
- marginLeft: props.theme.spacing(8),
- marginRight: props.theme.spacing(8),
- marginBottom: props.theme.spacing(8),
+ marginBottom: props.theme.spacing(20),
+ marginTop: props.theme.spacing(24),
}));
const TransparentButtonContainer = styled.div((props) => ({
@@ -49,12 +48,10 @@ const TransparentButtonContainer = styled.div((props) => ({
const Button = styled.button((props) => ({
display: 'flex',
flexDirection: 'row',
- justifyContent: 'flex-end',
- alignItems: 'center',
borderRadius: props.theme.radius(1),
backgroundColor: 'transparent',
width: '100%',
- marginTop: props.theme.spacing(5),
+ marginTop: props.theme.spacing(10),
}));
const ButtonText = styled.div((props) => ({
@@ -100,7 +97,7 @@ function ConfirmStxTransationComponent({
const [buttonLoading, setButtonLoading] = useState(loading);
const handleBackButtonClick = () => {
- navigate('/send-stx');
+ navigate(-1);
};
useEffect(() => {
@@ -191,24 +188,25 @@ function ConfirmStxTransationComponent({
onApplyClick={applyTxSettings}
onCrossClick={closeTransactionSettingAlert}
/>
-
-
-
+
+
+
+
+
-
+
+
-
-
>
);
}
diff --git a/src/app/components/sendForm/index.tsx b/src/app/components/sendForm/index.tsx
index eb662857f..166a4dd8b 100644
--- a/src/app/components/sendForm/index.tsx
+++ b/src/app/components/sendForm/index.tsx
@@ -2,7 +2,9 @@ import { CurrencyTypes } from '@utils/constants';
import { FungibleToken } from '@secretkeylabs/xverse-core/types';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
-import { SetStateAction, useState } from 'react';
+import {
+ ReactNode, SetStateAction, useEffect, useState,
+} from 'react';
import BigNumber from 'bignumber.js';
import IconBitcoin from '@assets/img/send/ic_sats_ticker.svg';
import IconStacks from '@assets/img/dashboard/stack_icon.svg';
@@ -146,6 +148,7 @@ interface Props {
hideMemo?: boolean;
buttonText?: string;
processing?: boolean;
+ children?: ReactNode;
}
function SendForm({
@@ -158,11 +161,13 @@ function SendForm({
hideMemo = false,
buttonText,
processing,
+ children,
}: Props) {
const { t } = useTranslation('translation', { keyPrefix: 'SEND' });
const [amount, setAmount] = useState('');
const [memo, setMemo] = useState('');
const [fiatAmount, setFiatAmount] = useState('0');
+ const [showError, setShowError] = useState(error);
const [recipientAddress, setRecipientAddress] = useState('');
const {
stxBtcRate, btcFiatRate, fiatCurrency, stxAddress,
@@ -176,6 +181,16 @@ function SendForm({
currencyType,
);
+ useEffect(() => {
+ if (error) {
+ if (associatedAddress !== '' && error.includes(t('ERRORS.ADDRESS_INVALID'))) {
+ setShowError('');
+ } else {
+ setShowError(error);
+ }
+ }
+ }, [error, associatedAddress]);
+
function getFiatEquivalent(value: number) {
if ((currencyType === 'FT' && !fungibleToken?.tokenFiatRate) || currencyType === 'NFT') {
return '';
@@ -296,13 +311,14 @@ function SendForm({
}
const handleOnPress = () => {
- onPressSend(associatedAddress !== '' ? associatedAddress : recipientAddress, amount, memo);
+ onPressSend(associatedAddress !== '' ? associatedAddress : debouncedSearchTerm, amount, memo);
};
return (
{!disableAmountInput && renderEnterAmountSection()}
+ {children}
{renderEnterRecepientSection()}
{currencyType !== 'BTC' && currencyType !== 'NFT' && !hideMemo && (
<>
@@ -328,7 +344,7 @@ function SendForm({
)}
- {error}
+ {showError}
diff --git a/src/app/components/transferFeeView/index.tsx b/src/app/components/transferFeeView/index.tsx
index ce8fac7c0..1a96130bd 100644
--- a/src/app/components/transferFeeView/index.tsx
+++ b/src/app/components/transferFeeView/index.tsx
@@ -10,7 +10,7 @@ import styled from 'styled-components';
const RowContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'row',
- marginTop: props.theme.spacing(6),
+ marginTop: props.theme.spacing(8),
}));
const FeeText = styled.h1((props) => ({
diff --git a/src/app/screens/confirmNftTransaction/index.tsx b/src/app/screens/confirmNftTransaction/index.tsx
index d4e8fb4f7..1a437556e 100644
--- a/src/app/screens/confirmNftTransaction/index.tsx
+++ b/src/app/screens/confirmNftTransaction/index.tsx
@@ -11,7 +11,7 @@ import { StoreState } from '@stores/index';
import BottomBar from '@components/tabBar';
import { fetchStxWalletDataRequestAction } from '@stores/wallet/actions/actionCreators';
import RecipientAddressView from '@components/recipinetAddressView';
-import ConfirmStxTransationComponent from '@screens/confirmStxTransaxtion/confirmStxTransactionComponent';
+import ConfirmStxTransationComponent from '@components/confirmStxTransactionComponent';
import useNftDataSelector from '@hooks/useNftDataSelector';
import NftImage from '@screens/nftDashboard/nftImage';
diff --git a/src/app/screens/confirmStxTransaxtion/index.tsx b/src/app/screens/confirmStxTransaxtion/index.tsx
index b4e2a4498..f12af79bd 100644
--- a/src/app/screens/confirmStxTransaxtion/index.tsx
+++ b/src/app/screens/confirmStxTransaxtion/index.tsx
@@ -13,7 +13,7 @@ import { StoreState } from '@stores/index';
import BottomBar from '@components/tabBar';
import { fetchStxWalletDataRequestAction } from '@stores/wallet/actions/actionCreators';
import RecipientAddressView from '@components/recipinetAddressView';
-import ConfirmStxTransationComponent from './confirmStxTransactionComponent';
+import ConfirmStxTransationComponent from '../../components/confirmStxTransactionComponent';
const InfoContainer = styled.div((props) => ({
display: 'flex',
diff --git a/src/app/screens/sendNft/index.tsx b/src/app/screens/sendNft/index.tsx
index 8a7053730..e479e6317 100644
--- a/src/app/screens/sendNft/index.tsx
+++ b/src/app/screens/sendNft/index.tsx
@@ -17,15 +17,6 @@ import { checkNftExists } from '@utils/helper';
import NftImage from '@screens/nftDashboard/nftImage';
import useNftDataSelector from '@hooks/useNftDataSelector';
-const OuterContainer = styled.div`
-display: flex;
-flex-direction: column;
-flex: 1;
-overflow-y: auto;
-&::-webkit-scrollbar {
- display: none;
-}`;
-
const Container = styled.div({
display: 'flex',
flexDirection: 'column',
@@ -154,25 +145,26 @@ function SendNft() {
}
};
return (
-
+ <>
-
-
-
-
- {nft?.token_metadata.name}
-
+ >
+
+
+
+
+ {nft?.token_metadata.name}
+
+
-
+ >
);
}
From 961e25d16d7e78547a666a718aa76fef19170be7 Mon Sep 17 00:00:00 2001
From: Imamah-Zafar <88320460+Imamah-Zafar@users.noreply.github.com>
Date: Fri, 18 Nov 2022 13:48:18 +0500
Subject: [PATCH 10/10] disable nft video autoplay
---
src/app/screens/nftDashboard/nftImage.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/screens/nftDashboard/nftImage.tsx b/src/app/screens/nftDashboard/nftImage.tsx
index c6080b124..eff08eb08 100644
--- a/src/app/screens/nftDashboard/nftImage.tsx
+++ b/src/app/screens/nftDashboard/nftImage.tsx
@@ -48,7 +48,7 @@ function NftImage({ metadata }: Props) {
if (metadata?.asset_protocol) {
return (
-
+
);
}