From 2341c61a3c1b32ff8525db4752de1d59b7552881 Mon Sep 17 00:00:00 2001 From: Matias Benary Date: Tue, 20 Aug 2024 19:08:24 -0300 Subject: [PATCH 1/8] fix: added error handling for catalogSearch --- src/components/sidebar-navigation/Search.tsx | 2 +- src/utils/catalogSearchApi.ts | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/sidebar-navigation/Search.tsx b/src/components/sidebar-navigation/Search.tsx index b5f3a8ed2..b0360120e 100644 --- a/src/components/sidebar-navigation/Search.tsx +++ b/src/components/sidebar-navigation/Search.tsx @@ -32,7 +32,7 @@ export const Search = ({ inputRef }: { inputRef: any }) => { const renderResults = useCallback( (type: TabType, rawResp: any) => { - if (!rawResp || (Array.isArray(rawResp.hits) && !rawResp.hits.length)) { + if (!rawResp || (Array.isArray(rawResp.hits) && !rawResp.hits.length) || rawResp?.error) { return
No results found for "{debouncedSearchTerm}"
; } diff --git a/src/utils/catalogSearchApi.ts b/src/utils/catalogSearchApi.ts index 8f0cfe073..b841d4e56 100644 --- a/src/utils/catalogSearchApi.ts +++ b/src/utils/catalogSearchApi.ts @@ -1,4 +1,14 @@ export const fetchCatalog = async (query: string) => { - const response = await fetch(`https://nearcatalog.xyz/wp-json/nearcatalog/v1/search?kw=${query}`); - return await response.json(); + try { + const response = await fetch(`https://nearcatalog.xyz/wp-json/nearcatalog/v1/search?kw=${query}`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error('Error fetching catalog:', error); + return { error: (error as Error).message }; + } }; From 98994392b427d7cb93d52f507fac85d444df7310 Mon Sep 17 00:00:00 2001 From: Matias Benary Date: Fri, 30 Aug 2024 08:51:30 -0300 Subject: [PATCH 2/8] wip --- src/components/sidebar-navigation/Sidebar.tsx | 7 + src/components/tools/MintNft.tsx | 154 ++++++++++++++++++ src/components/tools/NonFungibletoken.tsx | 13 ++ src/pages/tools.tsx | 73 +++++++++ 4 files changed, 247 insertions(+) create mode 100644 src/components/tools/MintNft.tsx create mode 100644 src/components/tools/NonFungibletoken.tsx create mode 100644 src/pages/tools.tsx diff --git a/src/components/sidebar-navigation/Sidebar.tsx b/src/components/sidebar-navigation/Sidebar.tsx index 2e1e9c2f3..e79b8aa63 100644 --- a/src/components/sidebar-navigation/Sidebar.tsx +++ b/src/components/sidebar-navigation/Sidebar.tsx @@ -110,6 +110,13 @@ export const Sidebar = () => { + + + + Tools + + + diff --git a/src/components/tools/MintNft.tsx b/src/components/tools/MintNft.tsx new file mode 100644 index 000000000..f6b13fa6d --- /dev/null +++ b/src/components/tools/MintNft.tsx @@ -0,0 +1,154 @@ +import { Button, Flex, Form, Input, openToast, Text } from '@near-pagoda/ui'; +import { useContext, useEffect, useState } from 'react'; +import type { SubmitHandler } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { NearContext } from '../WalletSelector'; + +type FormData = { + title: string; + description: string; + image: FileList; +}; + +const MAX_FILE_SIZE = 5 * 1024 * 1024; +const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml']; + +const MintNft = () => { + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm(); + const [imagePreview, setImagePreview] = useState(null); + + const { wallet, signedAccountId } = useContext(NearContext); + + const validateImage = (files: FileList) => { + if (files.length === 0) return 'Image is required'; + const file = files[0]; + if (file.size > MAX_FILE_SIZE) return 'Image size should be less than 5MB'; + if (!ACCEPTED_IMAGE_TYPES.includes(file.type)) return 'Not a valid image format'; + return true; + }; + + const onImageChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onloadend = () => { + setImagePreview(reader.result as string); + }; + reader.readAsDataURL(file); + } + }; + + const onSubmit: SubmitHandler = async (data) => { + if (!wallet) throw new Error('Wallet has not initialized yet'); + console.log(crypto.randomUUID()); + try { + let file = ''; + + if (data.image[0]) { + const res = await fetch('https://ipfs.near.social/add', { + method: 'POST', + headers: { Accept: 'application/json' }, + body: data.image[0], + }); + file = await res.json(); + file = file.cid; + } + + const args = { + receiver_id: signedAccountId, + token_id: crypto.randomUUID(), + token_metadata: { + media: `https://ipfs.near.social/ipfs/${file}`, + title: data.title, + description: data.description, + }, + }; + + const string_args = JSON.stringify(args); + + // TODO: Improve, we estimate the cost as 3 times the cost of storing the args + const cost_per_byte = 10 ** 19; + const estimated_cost = string_args.length * cost_per_byte * 3; + + const result = await wallet.signAndSendTransactions({ + transactions: [ + { + receiverId: storeSelected.name, + actions: [ + { + type: 'FunctionCall', + params: { + methodName: 'nft_mint', + args, + gas: '300000000000000', + deposit: estimated_cost, + }, + }, + ], + }, + ], + }); + + openToast({ + type: 'success', + title: 'Form Submitted', + description: 'Your form has been submitted successfully', + duration: 5000, + }); + } catch (error) { + openToast({ + type: 'error', + title: 'Error', + description: 'Failed to submit form', + duration: 5000, + }); + } + }; + + return ( + <> + Mint NFT +
+ + + +
+ + + {errors.image && {errors.image.message}} + {imagePreview && Preview} + + Accepted Formats: PNG, JPEG, GIF, SVG | Ideal dimension: 1:1 | Max size: 5MB + +
+