From 84b6325f91b17e3f1763279f47c012dbf55f4c3f Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 12 Dec 2023 10:36:09 -0300 Subject: [PATCH 001/305] feat: add onest-font in application - add onest font in all {content] --- pages/_app.tsx | 10 +++++++++- public/fonts/Onest-VariableFont_wght.woff2 | Bin 0 -> 57500 bytes tailwind.config.ts | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 public/fonts/Onest-VariableFont_wght.woff2 diff --git a/pages/_app.tsx b/pages/_app.tsx index 9c01cee7..771a650d 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -19,6 +19,12 @@ import { import { RainbowKitSiweNextAuthProvider } from "@rainbow-me/rainbowkit-siwe-next-auth"; import { SwapContextProvider } from "@/components/01-atoms"; import { Toaster } from "react-hot-toast"; +import localFont from "next/font/local"; + +const onest = localFont({ + src: "../public/fonts/Onest-VariableFont_wght.woff2", + variable: "--font-onest", +}); function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { return ( @@ -46,7 +52,9 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { chains={chains} > - +
+ +
diff --git a/public/fonts/Onest-VariableFont_wght.woff2 b/public/fonts/Onest-VariableFont_wght.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..277374c41bf2a9f58eabb83790dcbd77d04aa558 GIT binary patch literal 57500 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%0Aw7r=jlnFxXyM_Uj@0 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%0Do8F}0wHP!M@(8W%c5}{~L z$jFDfYDb0Kc%wdWvhQ++q&&~D^2@I5P!+FYI|>zQO)}YWobgR7^8~n@s4kmevze3o_IvJpHmW~5GRXIqLt-&Q(?QM!rzAoG ziw=b{LnS&3$4``-Jl0Q14})PU8Gej0@;y%{ zi@Oa>8q4$iE_q72t?%dSS#I!@9!dY(88e!doTgnNLkbY?{`E2%pfsr$jBmxY%d`@+ z_qMHvQ_WM?3kU`2JOFA#!emYXKIXA5eqN8;QDpVl2$fs_ zUz^oZ?ap79GhIZmi-^3luc{OZgtBpbXA-GmDep`e0xNxN5{#vsHzd^P8tM{!D42OLRf21X~0Q0axpEJW#UfyoMe(#PM z2tV!tZ`!;5Sx-^kOHus8V&AzGNw<@u3CT`&d=z$teM)UM_>^NR8!8?f)~_|eauU}- z++quF;nq>%V?6z_%rzev16VoD*c}~K$d@44()}6OcZDy2+17$tNN4#<&I_U!LfKN$i}&8#K!D!^JJF8sA< z(dysU_|JX+51BGF_nhaatPA+r`TqyDI1p=2>>V^R=YHpt^UwCuN?ST1xh$bX)TXnK z_rxes;3Iy*FH3${BN)ep=q~#Yg;vUsm1J zT>x&FZgTm*)Ge{euFKtdrk& zYgbO~uf7UT;ZGZ(z0AWELNl-aYq)`P)A`fupQt)K9D)_*`X=7%Z2z;pXCw|M4=g~5 zBW>b}X}>FbY^^Jt#f{3(_PJ#XtgGF3HkWI7VkvQ>S$P$nT8EcnSfTCmz9UMn$V@l( zumcI6jWSRq8?yA2N*h0Or)#D4a(8^ZEE1o^6AR5lC6NlJGOj^`q3(K~6%|W7L7-Sn z;2_dX-U7vKo_BAu9~Q<@QfrM?w2e^tL%JfXGEWx4_r03a@W8!H<~(1+5l{kFsXFUk zt6{to&UmL8E4`i*`vOn)TNVoWvGtFXhM9%lwJjm`{%9@T$>9m2vfgXc1=1l?X-U>| zVx1s!O`BmEPs$Nvup`T0#7y*Ch;VR;JV7zb=iLS!mxuNbzL>-q^7Fk z)Y^juS$}IK{)myJiLHvL6!^Kal1RX+RxvAZ%?-mgn+#))YtlfgyJ&nmi6}|-Phl*p zYF+HXb{}F>2m&q0s#{)v?pW%V`)vD0Z~Rq%`;^@PYvE97ZpTlJ!XuJU?w3 zW*oGa!t`wxDllf9E`#>UEEDbB_)O|bR&Y7L)?44x+YuKJt*4Fd)>u70) zv195i6DXscim4W>!@f>I!!Wrvu@jOIBzys{3BE*q%HWXD0K}6OBV`_l@ZI4MD9pT8 z4?`zXQ6Rs%HB%&W9pqx-b^m>%N~pn*FnBVisv9Gq$~10!gR_xJh>jtkA|0RFoFw_N zEf4rs$;k9!IA7>4Uw8cO*6Ee^beznBgPE=VBz--U%in#6)*yG~S+j?S=C=#>n}^)S z1bcR=4_@AicTJp*g<{HPz1^3ut)qP0k5?l4crW*< zx!4@55?$hN6^&kkDe!7%dhi<$QK z)ZyO74Ft;=O>WPn^SX7&o{fwDk(0(-XWsIHoWaizCknRHi4g?e`E9xt?$EmB*Jo7A3Q#Z3~%rE@zlMW z(ksG&-r`2Hz+U(lKPTY4yBrp9pZU0NvVY=wg3e^8xRa;9c*mOZ3N;b_zqgY^=l~hj z%~3K+H)bTE*M@4gtdtF-IN8u~{7)K?K-r$FJGTh66fASQhmb4)Y7>+xlsJ9tBM5dB zwUv@Wh<5X)`gF6qpp$^do9%hn&c}ihD&k)4PUsxZS)4Xx) z5|%?pt?K}7S5p_YaMmJ)n`BwV+5}rM-#=WWLX6(gZq27eGdr28z>p-iv@41y5AiA) zP8s`~LzuH=AmAvcZ=^F*Bi3Hevb>ZSA8Y`2q`f=J~XO6r9}?eQyfh4W=s zB>IDPECU=Ui-a;2J?nl#p4D5?bzMlR`1Akz{M*rbF#hg;oa6q4Pudl0m*UiDr@+Kv z;2k8}?j&<@W_@iH)1sw2kQur*Q!|cGMhMC)^O{TFO`T-TU%c!t;U?^mu(-v-td+Z_ znLR|=iW}I!+;k4x@4WWmZ^!Tm_cK--(= z;(FAb5D)w1BFgL~?JdOqnEJ`~=DH|=Iv|JH3om1X#O}nEux0LQ(KqC9LTtk}ha=L4 zC`{Z!G8k8O&qd3hkXAw@G-J4>mJzG9-91PDtk(5htB!HE_TVwPA8^W=H~9PHi(4OE zc7V77ILPW*HR5jkejMGJSb630BN^VEhedkMlj^6PTh8m|UON{<1Vrdj-)bd!yeub~ zK-X7;a#)gUsj4ZXiRhF^SUGNAN4|Y%?X(co&m9Cq!UI;vDDGZz! zY^&39PqJ-nH3d*Ekyrr4L`H}j$nTO_5qVwLI#^b-g#;>Pbgn^T=MVX^Pyv7z$z7X#<#yqABvTNh%~M zhArk1lU6;X$w!{6GcSQZ82P57 zTJyRkp6iN7re#R~5@rp5n*lekLhpUZ7N&}#D5}y4^7?tfU(uU8o`JS%cErU0H&LHyN;t|<~tWb%<{cMwp_?`f4lUkYOKR!NG| zx}V6nqMXh>W+06f$;ly>-?(I>R-75*g8`a=MT$$&gjPu`Rl?4;_B8v;y|~DC$ujrr z+xEdohUd|IDv^@ct*VJ+VZklu@!+Ebv}|_62PU22;-{MIl=m#27GOB>mvs4l5Q=&u zTh#n)_a`f?FI%=B4xv`H9M?Ag|J!e>UAZ%$`o2nTk^d8{<#MfEYCb9eRF7HZ@{6^> zn>kJ9rhG!EwkZwFLHWZPVGk0{(M^f9pYxTSB?=%22iGL^LpU}F&}r<^PSAD+dVKN0 zo_v=Hm;E4cRVw9f++A?OhgZ7*D4-)ZV7GQa1yY*5@L;Pyr*Hb8_RmH*N9Vv|)Vlq- zkPvsEpEjP2TjynE!-2%mHg1HEze-Q(X1Hj80(TR$I6T%2-h$r<=ovA_Z~i zaJ{5H4|rICnx(t|YTe&hNTwBK&}rMGsMTV0)XYH`?T3s!LQ?lu=gB$hz#U5#dxwc> zs_HoNJDs9aq^ZS}iwkJj_5tB{Wx8>Tcw)|@(M7!fuA7cN zn-CJEb}4|p6BxN+1G_4PZhDQxc>X(C@1twupS$D+t!FMt?AWteSMAW{7%7gcoZ0Uh z$0sW|o6A`IZLL~z>>>~Au(dT#Kms?Kn`w06g`!kG;(2IN5WZ=A*72ljbqnwS z7{ZPMTjyP1;yV8QrUckPNNok}KtKLY1%O}_{G<_5Ua1y;N1b{)sn-cYE1$mNU^NUM zvrFAKLo1|@9aH!nZ%1|WF#U`I0uuGNuO(3o?jg<|UH4RaXHh}nuIps05gwFXfXEGo zHVGKW|0FPJSmCp>|CC&}|52$S^yr_u<#*7RXdGdH2rZE{&g>t_=RSF4SqwGFL_((< zYG|pp?abP-&(rrt^GOsmC|r1f(k3yKfWe7tgCEIl2^~>1jW_*23t^Hn{qLJgum@fo z&dyFfTtIlQ)0&$NuZA`WOcr$ZB%dRS_FnOPyWWQ5G^$(DV7xLAboFle|Chn2ow~ni zj2aB!!Ga>J|9xBjZF9gW&fGQ*zG+w&6%&}-n z(UJ6ho}1rbcIOA&-Ooy3AJhakt>_qE8a6B4_2s#I(2o~6P2zjZ-NN3R{fYga*Fqy@ z-FajdS!Gi!C(m}B6=pqe?%v5AG}-tSE*unp|i4i(RCY z98ZFA)A-&aKhe6d=ru{KU7W4Dw5ZvPk)8L&<%O+i=xjZ&{qT2U(|74ayJw2DS2!~x+tMV z=)krB@41^@ms4uGwVe&wjge26UpFt1Mjgt}=7R~CER+vHMxP}4&Rh~j<(G?z$LfEQ zK8xi<52EN{r#bKJJvI~;-p2n8pIh9Jm=u;wWxb8l5+9>7BOga?9S zq?Oj;+dOQiatYo{ELjSeWE_2phlX-%r0H8>+1r^B;ZtcQ4`x`xcW$4)?)$L7nGF5? zh+V&-pH}2Wv*(cwnS|Uj7OfbiPjvyR?+j^>mcEr4QOQCBq10@>p72Sz!Jh_*FRW*3 zTOPzefPve&k>7UavzZx;jr0aR-Oqm3w#~ftgwi1T0Sh^jTg|C=XESeBJL591WtNj; zJESI}T_OPPIZV930TVDEoPC(N?HnLV6*=lJtiWIJpr`XZrG~u=9(tC56a~LS72HSZ zN%jB|AwiA=c0e4Yy3ax@+IAT%HGRc1_CmhH;;NffMc_33r1VNJcJdZ3(t|Oexot_m z*kMndMYjB2n3c`(WwHHPZCeF3Z@Dj!c15p84*{ES#)KrG`wi9o?4;>$$-rw(=kL9Y zN{nJDL2OT!QdsZMQW~ADTgu?Ngv>^6!%{AOJ+J0rsQ_i)v=lBC$*^Nf#W<>{(zdc4 z0+cKSpu3PhKQacHirh&{X;27U$^akFDt1dr9NX`GuK0MK=hCtW2rYwXRIc zsGNI|(_f{$N=<_jKOh4NF=`Gk6E1*)Qm_J8RcnL9V4+3{i7hpsm$PB{swz!YN+}x2 zq$-g*JLgiG)1Xw^hy`+?DRW*z7d(RNuFp{OM9?lW{R+FE?e=Y#xKl{YJJVQ$u5zapAJ_!e#}^M z>9Sp|PSk5fX_aR}#7@p`IJfjxZ=?k*s?UFSZo>kFfLx?xtJ)Zkg29>wIixI;Z_buU z&w42~7ST5~=-4VS5fG7j#+prJ6x6b!W$SuD-H`28!I-Ue$YFN=W6vQLHcpOl zd+v)O@fGHjfRKndXSYk}jvRMOBqOJw%!O+zYDF};aW_)ij_20Ybp2ayeNqozP&4xJ7v!Fz0+lGO ztm1+~!XnKqD%Pyx5(QVTLZzzy79zB2HEPv0zxu)~sG&s`TUeu}S}gI4a4$uOtXYfJ zqH60OUo}m8D@3e|1teZwHJrDYz!t2;Dl)?%k!t>So5_u21&gRSHEAB7$B zt6s;QaMCHKo$4hOz_{5Nojh8x|fh&G_tT&SW@XtZ92n;sa- zm;oDZ?piNgA@knKav)a2jDyIBf$`LMdbu6cJ)?g`lD)AkkPU;`p_JISHe zO?H*n+BfL_2RPEPr{cLDo^Xff@^pwkZ0kXQ!Vw_XPtui0WGF?-NuOdTIq8dBuzN9SG8?xd^Cd=0KGhihaXvK&5}1^cLiDYDD5g2~Sue3YA7@Ftf-SH$gFh z$vkevNx}-EGU(Fc;w@D+A6q!&r*e3cIPQ6HQI}1n+xeb=DEj{e&!uBsoQ~93H+z$TqTGHzx=yhpt?|Il^fm*M z3GFgKGHG;~OI5Pcg>?gbO{51Mujm47-F4Q9`wNiVe?Rd`*Zn2PEgPhkZDXgkjr)-} z+V1KOx}h8xQmR|yu!G%bic+;z=_sOV~FIUo8fw6wPj!BwgC?4wttuE~0PIqH^Z?67QPP#`~Y006c?Shnk zDzCQFdOroJ@e$d^f;;+st&hq23HyXO?%@u-U7K!;V4O}unL90zJ3GrO6{+bje>uPh zTN|zVf9_8zeIZxvb0yM2gi7>zs1tV3j|x=J)l2aG#_>)To3?H)QUMb4qS5r70ui?O KAIInc0000%F`JYC literal 0 HcmV?d00001 diff --git a/tailwind.config.ts b/tailwind.config.ts index ce518de3..76e2f22b 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -5,6 +5,14 @@ const config: Config = { "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", ], + theme: { + extend: { + fontFamily: { + onest: ["var(--font-onest)"], + }, + }, + }, + plugins: [], }; export default config; From c61f1909e8c76c3bdb098136f18cfb6e192dfa8d Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 18 Dec 2023 11:52:24 -0300 Subject: [PATCH 002/305] feat: add fonts & dark/light mode - add onest font - add dark/light mode - change text-fonts and color switching light/dark - add new layout like figma --- components/01-atoms/ConnectWallet.tsx | 4 +- components/01-atoms/SearchBar.tsx | 31 +++++++++---- components/01-atoms/SelectAuthedUserChain.tsx | 2 +- components/01-atoms/SelectDestinyChain.tsx | 2 +- components/01-atoms/Tab.tsx | 8 ++-- components/01-atoms/icons/PersonIcon.tsx | 22 ++++++++++ components/01-atoms/icons/SelectUserIcon.tsx | 23 ++++++++++ components/01-atoms/icons/SwaplaceIcon.tsx | 6 +-- components/01-atoms/icons/WalletIcon.tsx | 22 ++++++++++ components/02-molecules/CardHome.tsx | 8 ++-- components/02-molecules/NftCard.tsx | 2 +- components/02-molecules/OfferSummary.tsx | 11 +++-- components/02-molecules/SwapStation.tsx | 14 +++--- components/02-molecules/TheHeader.tsx | 41 +++++++++++++++--- components/03-organisms/NftsShelf.tsx | 29 +++++++++---- components/03-organisms/SwappingShelfs.tsx | 2 +- components/04-templates/SwapSection.tsx | 4 +- package-lock.json | 11 +++++ package.json | 1 + pages/_app.tsx | 10 +++-- pages/_document.tsx | 2 +- styles/global.css | 43 ++++++++++++++++++- tailwind.config.ts | 1 + 23 files changed, 243 insertions(+), 56 deletions(-) create mode 100644 components/01-atoms/icons/PersonIcon.tsx create mode 100644 components/01-atoms/icons/SelectUserIcon.tsx create mode 100644 components/01-atoms/icons/WalletIcon.tsx diff --git a/components/01-atoms/ConnectWallet.tsx b/components/01-atoms/ConnectWallet.tsx index 4be484ff..f53d0c54 100644 --- a/components/01-atoms/ConnectWallet.tsx +++ b/components/01-atoms/ConnectWallet.tsx @@ -65,7 +65,7 @@ export const ConnectWallet = ({ customStyle }: IConnectWallet) => {
-
+
-

Your network:

+

Your network:

-

Searched address network:

+

+ Searched address network: +

diff --git a/components/01-atoms/SelectAuthedUserChain.tsx b/components/01-atoms/SelectAuthedUserChain.tsx index 8a8a9250..fc36125b 100644 --- a/components/01-atoms/SelectAuthedUserChain.tsx +++ b/components/01-atoms/SelectAuthedUserChain.tsx @@ -49,7 +49,7 @@ export const SelectAuthedUserChain = () => {
+ ) : ( + + )} +
+
+ +
+
); }; diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 5ecfbcac..904e498f 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -11,6 +11,8 @@ import { getNftsFrom } from "@/lib/client/blockchain-data"; import { SwapContext, SwapIcon } from "../01-atoms"; import { EthereumAddress } from "@/lib/shared/types"; import { useNetwork } from "wagmi"; +import { SelectUserIcon } from "../01-atoms/icons/SelectUserIcon"; +import { useTheme } from "next-themes"; /** * @@ -29,6 +31,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { const [nftsQueryStatus, setNftsQueryStatus] = useState( NFTsQueryStatus.EMPTY_QUERY ); + const { theme } = useTheme(); const { authenticatedUserAddress } = useAuthenticatedUser(); const { validatedAddressToSwap, inputAddress, destinyChain } = @@ -86,7 +89,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? ( @@ -94,26 +97,34 @@ export const NftsShelf = ({ address }: INftsShelfProps) => {
) : nftsQueryStatus == NFTsQueryStatus.EMPTY_QUERY || !address ? ( -
+
- -

- Select a user to start swapping +

+ +
+

+ No user selected yet +

+

+ Search for a user to start swapping items

) : nftsQueryStatus == NFTsQueryStatus.NO_RESULTS ? ( -
+
-

+

Given address has no NFTs associated in the given network

) : nftsQueryStatus == NFTsQueryStatus.LOADING ? ( -
+
-

+

Loading NFTs of{" "} {new EthereumAddress(address).getEllipsedAddress()}...

diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index bfbcc9c5..59e5ee63 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -25,7 +25,7 @@ export const SwappingShelfs = () => { }, [chain]); return ( -
+
setActiveSwappingShelfID(input)} /> diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 33651c15..86da397f 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -4,8 +4,8 @@ import { SwapStation } from "@/components/02-molecules"; export const SwapSection = () => { return ( -
-
+
+
diff --git a/package-lock.json b/package-lock.json index 356115bf..892b6322 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "ethers": "^5.7.2", "next": "14.0.3", "next-auth": "^4.20.1", + "next-themes": "^0.2.1", "react": "^18", "react-dom": "^18", "react-hot-toast": "^2.4.1", @@ -6633,6 +6634,16 @@ } } }, + "node_modules/next-themes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", + "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", + "peerDependencies": { + "next": "*", + "react": "*", + "react-dom": "*" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", diff --git a/package.json b/package.json index 5af5469c..ffe53967 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "ethers": "^5.7.2", "next": "14.0.3", "next-auth": "^4.20.1", + "next-themes": "^0.2.1", "react": "^18", "react-dom": "^18", "react-hot-toast": "^2.4.1", diff --git a/pages/_app.tsx b/pages/_app.tsx index 771a650d..3a4a3b0e 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -20,6 +20,8 @@ import { RainbowKitSiweNextAuthProvider } from "@rainbow-me/rainbowkit-siwe-next import { SwapContextProvider } from "@/components/01-atoms"; import { Toaster } from "react-hot-toast"; import localFont from "next/font/local"; +import cc from "classcat"; +import { ThemeProvider } from "next-themes"; const onest = localFont({ src: "../public/fonts/Onest-VariableFont_wght.woff2", @@ -52,9 +54,11 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { chains={chains} > -
- -
+ +
+ +
+
diff --git a/pages/_document.tsx b/pages/_document.tsx index cec067eb..1ccd8e8e 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -4,7 +4,7 @@ export default function Document() { return ( - +
diff --git a/styles/global.css b/styles/global.css index 69c92b45..fdd36631 100644 --- a/styles/global.css +++ b/styles/global.css @@ -1,11 +1,52 @@ html, body { - width: 100vw; overflow-x: hidden; } + input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { display: none; } + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer utilities { + .title-h1 { + } + + .title-h2 { + } + + .title-h3-normal { + @apply font-onest font-normal text-[20px] leading-[25.5px] text-[#333333]; + } + + .title-h3-normal-dark { + @apply font-onest font-normal text-[20px] leading-[25.5px] text-[#F6F6F6]; + } + + .p-medium-bold { + @apply font-onest font-medium text-[14px] leading-[16px] text-[#707572]; + } + .p-medium-bold-dark { + @apply font-onest font-medium text-[14px] leading-[16px] text-[#F6F6F6]; + } + + .p-medium { + @apply font-onest font-medium text-[14px] leading-[20px] text-[#707572]; + } + .p-medium-dark { + @apply font-onest font-medium text-[14px] leading-[20px] text-[#F6F6F6]; + } + + .p-small { + @apply font-onest font-normal text-[14px] leading-[20px] text-[#707572]; + } + .p-small-dark { + @apply font-onest font-normal text-[14px] leading-[20px] text-[#F6F6F6]; + } +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 76e2f22b..623c4e09 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,6 +1,7 @@ import type { Config } from "tailwindcss"; const config: Config = { + darkMode: ["class"], content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", From cb6b3281901186ef248501284d900a7d15430014 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 18 Dec 2023 12:46:29 -0300 Subject: [PATCH 003/305] refactor: adjust imports - refactor all imports & remove unused --- components/01-atoms/ConfirmSwapModal.tsx | 10 +++------- components/01-atoms/LoadingIndicator.tsx | 4 +--- components/01-atoms/SearchBar.tsx | 4 ++-- components/01-atoms/SelectDestinyChain.tsx | 5 +++-- components/01-atoms/TransactionResultModal.tsx | 7 +++---- components/01-atoms/icons/index.tsx | 10 ++++++++++ components/01-atoms/index.ts | 8 +------- components/02-molecules/CardHome.tsx | 3 ++- components/02-molecules/NftCard.tsx | 2 +- components/02-molecules/NftsList.tsx | 2 +- components/02-molecules/OfferSummary.tsx | 7 ++++--- components/02-molecules/SwapStation.tsx | 7 ++----- components/02-molecules/TheHeader.tsx | 4 ++-- components/02-molecules/index.tsx | 6 +++--- components/03-organisms/NftsShelf.tsx | 17 ++++++----------- components/03-organisms/SwappingShelfs.tsx | 2 +- components/03-organisms/index.tsx | 1 + components/04-templates/SwapSection.tsx | 2 +- components/04-templates/index.tsx | 2 +- 19 files changed, 48 insertions(+), 55 deletions(-) create mode 100644 components/01-atoms/icons/index.tsx diff --git a/components/01-atoms/ConfirmSwapModal.tsx b/components/01-atoms/ConfirmSwapModal.tsx index f137efdb..a2f98317 100644 --- a/components/01-atoms/ConfirmSwapModal.tsx +++ b/components/01-atoms/ConfirmSwapModal.tsx @@ -1,12 +1,5 @@ import { Dialog, Transition } from "@headlessui/react"; import { Fragment, useContext, useEffect, useState } from "react"; -import { - NftCard, - NftCardActionType, - SwapContext, - SwapIcon, - TransactionResultModal, -} from "."; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { makeSwap } from "@/lib/client/blockchain-data"; import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants"; @@ -14,6 +7,9 @@ import { useNetwork, useWalletClient } from "wagmi"; import { getTimestamp } from "@/lib/client/utils"; import { signTransaction } from "viem/actions"; import toast from "react-hot-toast"; +import { SwapContext, TransactionResultModal } from "@/components/01-atoms"; +import { NftCard, NftCardActionType } from "@/components/02-molecules"; +import { SwapIcon } from "@/components/01-atoms/icons"; interface ConfirmSwapModalProps { open: boolean; diff --git a/components/01-atoms/LoadingIndicator.tsx b/components/01-atoms/LoadingIndicator.tsx index 1107a5db..d432d0ae 100644 --- a/components/01-atoms/LoadingIndicator.tsx +++ b/components/01-atoms/LoadingIndicator.tsx @@ -1,7 +1,5 @@ import React from "react"; -const LoadingIndicator = () => ( +export const LoadingIndicator = () => (
); - -export default LoadingIndicator; diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 72ae246f..d09f8835 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -1,11 +1,11 @@ import cc from "classcat"; import { useContext, useEffect, useState } from "react"; +import { MagnifyingGlassIcon } from "@/components/01-atoms/icons"; import { - MagnifyingGlassIcon, SelectAuthedUserChain, SelectDestinyChain, SwapContext, -} from "."; +} from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { ENS } from "web3-eth-ens"; import Web3 from "web3"; diff --git a/components/01-atoms/SelectDestinyChain.tsx b/components/01-atoms/SelectDestinyChain.tsx index 3372b70a..1e84ea76 100644 --- a/components/01-atoms/SelectDestinyChain.tsx +++ b/components/01-atoms/SelectDestinyChain.tsx @@ -1,6 +1,7 @@ -import { Dialog, Transition } from "@headlessui/react"; import { Fragment, useContext, useState } from "react"; -import { EthereumIcon, PolygonIcon, SwapContext } from "."; +import { Dialog, Transition } from "@headlessui/react"; +import { SwapContext } from "@/components/01-atoms"; +import { EthereumIcon, PolygonIcon } from "@/components/01-atoms/icons"; import { ChainInfo, SupportedNetworks } from "@/lib/client/constants"; import cc from "classcat"; diff --git a/components/01-atoms/TransactionResultModal.tsx b/components/01-atoms/TransactionResultModal.tsx index 464c8866..5dcb5385 100644 --- a/components/01-atoms/TransactionResultModal.tsx +++ b/components/01-atoms/TransactionResultModal.tsx @@ -1,9 +1,8 @@ -import { Dialog, Transition } from "@headlessui/react"; -import { TransactionResult } from "."; import { Fragment, useState } from "react"; -import LoadingIndicator from "./LoadingIndicator"; +import { Dialog, Transition } from "@headlessui/react"; +import { TransactionResult, LoadingIndicator } from "@/components/01-atoms"; +import { DangerIcon } from "@/components/01-atoms/icons"; import { CheckmarkIcon } from "react-hot-toast"; -import { DangerIcon } from "./icons/DangerIcon"; interface TransactionResultModalProps { onClose: () => void; diff --git a/components/01-atoms/icons/index.tsx b/components/01-atoms/icons/index.tsx new file mode 100644 index 00000000..7a2f2796 --- /dev/null +++ b/components/01-atoms/icons/index.tsx @@ -0,0 +1,10 @@ +export * from "./DangerIcon"; +export * from "./EthereumIcon"; +export * from "./MagnifyingGlassIcon"; +export * from "./PaperPlane"; +export * from "./PersonIcon"; +export * from "./PolygonIcon"; +export * from "./SelectUserIcon"; +export * from "./SwapIcon"; +export * from "./SwaplaceIcon"; +export * from "./WalletIcon"; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 988081da..0355c2c5 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -1,15 +1,9 @@ export * from "./ConnectWallet"; -export * from "../02-molecules/NftCard"; export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; export * from "./Tab"; export * from "./SwapContext"; -export * from "./icons/SwaplaceIcon"; -export * from "./icons/MagnifyingGlassIcon"; -export * from "./icons/SwapIcon"; -export * from "./icons/PaperPlane"; export * from "./SelectDestinyChain"; -export * from "./icons/EthereumIcon"; -export * from "./icons/PolygonIcon"; export * from "./ConfirmSwapModal"; export * from "./TransactionResultModal"; +export * from "./LoadingIndicator"; diff --git a/components/02-molecules/CardHome.tsx b/components/02-molecules/CardHome.tsx index d11bc641..ff440e52 100644 --- a/components/02-molecules/CardHome.tsx +++ b/components/02-molecules/CardHome.tsx @@ -1,5 +1,6 @@ import React from "react"; -import { ConnectWallet, SwaplaceIcon } from "@/components/01-atoms"; +import { ConnectWallet } from "@/components/01-atoms"; +import { SwaplaceIcon } from "@/components/01-atoms/icons"; export const CardHome = () => { return ( diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index df66d13b..614282f0 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -1,6 +1,6 @@ import { NFT } from "@/lib/client/constants"; import React, { useContext, useEffect, useState } from "react"; -import { SwapContext } from "../01-atoms"; +import { SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { EthereumAddress } from "@/lib/shared/types"; import cc from "classcat"; diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index 06fe1db1..f56fc33f 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -1,5 +1,5 @@ import { NFT } from "@/lib/client/constants"; -import { NftCard } from "../01-atoms"; +import { NftCard } from "@/components/02-molecules"; interface INftsList { nftsList: NFT[]; diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 5fe72c25..633b7d57 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -1,10 +1,11 @@ import { useContext } from "react"; -import { EthereumIcon, NftCard, PolygonIcon, SwapContext } from "../01-atoms"; import { useEnsName, useNetwork } from "wagmi"; import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { ChainInfo, SupportedNetworks } from "@/lib/client/constants"; -import { PersonIcon } from "../01-atoms/icons/PersonIcon"; +import { ChainInfo } from "@/lib/client/constants"; +import { SwapContext } from "@/components/01-atoms"; +import { PersonIcon } from "@/components/01-atoms/icons"; +import { NftCard } from "@/components/02-molecules"; interface IOfferSummary { forAuthedUser: boolean; diff --git a/components/02-molecules/SwapStation.tsx b/components/02-molecules/SwapStation.tsx index 889537ce..1831bf6b 100644 --- a/components/02-molecules/SwapStation.tsx +++ b/components/02-molecules/SwapStation.tsx @@ -1,10 +1,7 @@ import { useContext, useEffect, useState } from "react"; +import { ConfirmSwapModal, SwapContext } from "@/components/01-atoms"; +import { PaperPlane } from "@/components/01-atoms/icons"; import { OfferSummary } from "@/components/02-molecules"; -import { - ConfirmSwapModal, - PaperPlane, - SwapContext, -} from "@/components/01-atoms"; import cc from "classcat"; import toast from "react-hot-toast"; diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 4b61a8d0..17714bca 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from "react"; -import { ConnectWallet, SwaplaceIcon } from "@/components/01-atoms"; import cc from "classcat"; import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useTheme } from "next-themes"; -import { WalletIcon } from "../01-atoms/icons/WalletIcon"; +import { ConnectWallet } from "@/components/01-atoms"; +import { SwaplaceIcon, WalletIcon } from "@/components/01-atoms/icons/"; export const TheHeader = () => { const { isDesktop } = useScreenSize(); diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index 9ff6d1dd..d2a6e13e 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -1,6 +1,6 @@ export * from "./CardHome"; -export * from "./TheHeader"; -export * from "../03-organisms/NftsShelf"; +export * from "./NftCard"; export * from "./NftsList"; -export * from "./SwapStation"; export * from "./OfferSummary"; +export * from "./SwapStation"; +export * from "./TheHeader"; diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 904e498f..fcbda686 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -1,18 +1,13 @@ import { useContext, useEffect, useState } from "react"; -import { - NFT, - ChainInfo, - NFTsQueryStatus, - ADDRESS_ZERO, -} from "@/lib/client/constants"; +import { NFT, ChainInfo, NFTsQueryStatus } from "@/lib/client/constants"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { NftsList } from "../02-molecules"; -import { getNftsFrom } from "@/lib/client/blockchain-data"; -import { SwapContext, SwapIcon } from "../01-atoms"; -import { EthereumAddress } from "@/lib/shared/types"; import { useNetwork } from "wagmi"; -import { SelectUserIcon } from "../01-atoms/icons/SelectUserIcon"; +import { getNftsFrom } from "@/lib/client/blockchain-data"; import { useTheme } from "next-themes"; +import { EthereumAddress } from "@/lib/shared/types"; +import { SwapContext } from "@/components/01-atoms"; +import { SelectUserIcon } from "@/components/01-atoms/icons"; +import { NftsList } from "@/components/02-molecules"; /** * diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 59e5ee63..7732ff33 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -1,7 +1,7 @@ import cc from "classcat"; import { useContext, useEffect, useState } from "react"; -import { NftsShelf } from "@/components/02-molecules"; import { SwapContext, SwappingShelfID, Tab } from "@/components/01-atoms/"; +import { NftsShelf } from "@/components/03-organisms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useNetwork } from "wagmi"; diff --git a/components/03-organisms/index.tsx b/components/03-organisms/index.tsx index fa5458de..6ce0cddd 100644 --- a/components/03-organisms/index.tsx +++ b/components/03-organisms/index.tsx @@ -1 +1,2 @@ +export * from "./NftsShelf"; export * from "./SwappingShelfs"; diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 86da397f..476eef40 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -1,6 +1,6 @@ import { SearchBar } from "@/components/01-atoms"; -import { SwappingShelfs } from "@/components/03-organisms"; import { SwapStation } from "@/components/02-molecules"; +import { SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( diff --git a/components/04-templates/index.tsx b/components/04-templates/index.tsx index cf73a80e..a8ff2ccc 100644 --- a/components/04-templates/index.tsx +++ b/components/04-templates/index.tsx @@ -1,3 +1,3 @@ export * from "./HomeSection"; -export * from "./SwapSection"; export * from "./Layout"; +export * from "./SwapSection"; From f97e6b5936bbf9df0ed38c7a3493bb2a8293d222 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 18 Dec 2023 19:16:04 -0300 Subject: [PATCH 004/305] feat: add swaplace header icons - add header & icons changing with theme --- components/01-atoms/SwappingIcons.tsx | 109 ++++++++++++++++++ components/01-atoms/icons/ChatIcon.tsx | 22 ++++ .../01-atoms/icons/NotificationsIcon.tsx | 22 ++++ components/01-atoms/icons/OffersIcon.tsx | 22 ++++ components/01-atoms/icons/SwappingIcon.tsx | 22 ++++ components/01-atoms/icons/index.tsx | 4 + components/01-atoms/index.ts | 5 +- components/02-molecules/CardHome.tsx | 8 +- components/02-molecules/TheHeader.tsx | 26 +++-- 9 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 components/01-atoms/SwappingIcons.tsx create mode 100644 components/01-atoms/icons/ChatIcon.tsx create mode 100644 components/01-atoms/icons/NotificationsIcon.tsx create mode 100644 components/01-atoms/icons/OffersIcon.tsx create mode 100644 components/01-atoms/icons/SwappingIcon.tsx diff --git a/components/01-atoms/SwappingIcons.tsx b/components/01-atoms/SwappingIcons.tsx new file mode 100644 index 00000000..6ae7cacc --- /dev/null +++ b/components/01-atoms/SwappingIcons.tsx @@ -0,0 +1,109 @@ +import { useTheme } from "next-themes"; +import { useRouter } from "next/router"; +import { useState } from "react"; +import { + SwappingIcon, + OffersIcon, + ChatIcon, + NotificationsIcon, +} from "@/components/01-atoms/icons"; +import cc from "classcat"; + +export interface IconSwap { + id: number; + name: string; + href: string; + icon: React.ReactNode; +} + +export enum SwappingIconsID { + "SWAPLACE_STATION", + "OFFERS", + "CHAT", + "NOTIFICATIONS", +} + +export const SwappingIcons = () => { + const { theme } = useTheme(); + const [isActiveTab, setIsActiveTab] = useState( + SwappingIconsID.SWAPLACE_STATION + ); + + const swappingTabs: Array = [ + { + id: SwappingIconsID.SWAPLACE_STATION, + name: "Swaplace Station", + href: "/", + icon: ( + + ), + }, + { + id: SwappingIconsID.OFFERS, + name: "Offers", + href: "/offers", + icon: ( + + ), + }, + { + id: SwappingIconsID.CHAT, + name: "Chat", + href: "/", + icon: ( + + ), + }, + { + id: SwappingIconsID.NOTIFICATIONS, + name: "Notifications", + href: "/", + icon: ( + + ), + }, + ]; + + const router = useRouter(); + const handleClick = (e: IconSwap) => { + setIsActiveTab(e.id); + router.push(e.href); + }; + + return ( + <> + {swappingTabs.map((swapIcons) => { + return ( +
{ + handleClick(swapIcons); + }} + > +
+ {swapIcons.icon} +
+
+ ); + })} + + ); +}; diff --git a/components/01-atoms/icons/ChatIcon.tsx b/components/01-atoms/icons/ChatIcon.tsx new file mode 100644 index 00000000..ea420aa7 --- /dev/null +++ b/components/01-atoms/icons/ChatIcon.tsx @@ -0,0 +1,22 @@ +import { SVGProps } from "react"; + +export const ChatIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/NotificationsIcon.tsx b/components/01-atoms/icons/NotificationsIcon.tsx new file mode 100644 index 00000000..7b355411 --- /dev/null +++ b/components/01-atoms/icons/NotificationsIcon.tsx @@ -0,0 +1,22 @@ +import { SVGProps } from "react"; + +export const NotificationsIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/OffersIcon.tsx b/components/01-atoms/icons/OffersIcon.tsx new file mode 100644 index 00000000..81908e35 --- /dev/null +++ b/components/01-atoms/icons/OffersIcon.tsx @@ -0,0 +1,22 @@ +import { SVGProps } from "react"; + +export const OffersIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/SwappingIcon.tsx b/components/01-atoms/icons/SwappingIcon.tsx new file mode 100644 index 00000000..fa715eb0 --- /dev/null +++ b/components/01-atoms/icons/SwappingIcon.tsx @@ -0,0 +1,22 @@ +import { SVGProps } from "react"; + +export const SwappingIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/index.tsx b/components/01-atoms/icons/index.tsx index 7a2f2796..4bd5b2d1 100644 --- a/components/01-atoms/icons/index.tsx +++ b/components/01-atoms/icons/index.tsx @@ -1,10 +1,14 @@ +export * from "./ChatIcon"; export * from "./DangerIcon"; export * from "./EthereumIcon"; export * from "./MagnifyingGlassIcon"; +export * from "./NotificationsIcon"; +export * from "./OffersIcon"; export * from "./PaperPlane"; export * from "./PersonIcon"; export * from "./PolygonIcon"; export * from "./SelectUserIcon"; export * from "./SwapIcon"; export * from "./SwaplaceIcon"; +export * from "./SwappingIcon"; export * from "./WalletIcon"; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 0355c2c5..57ac5b33 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -1,9 +1,10 @@ export * from "./ConnectWallet"; export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; -export * from "./Tab"; -export * from "./SwapContext"; export * from "./SelectDestinyChain"; export * from "./ConfirmSwapModal"; export * from "./TransactionResultModal"; export * from "./LoadingIndicator"; +export * from "./SwapContext"; +export * from "./SwappingIcons"; +export * from "./Tab"; diff --git a/components/02-molecules/CardHome.tsx b/components/02-molecules/CardHome.tsx index ff440e52..4e97e37c 100644 --- a/components/02-molecules/CardHome.tsx +++ b/components/02-molecules/CardHome.tsx @@ -8,14 +8,14 @@ export const CardHome = () => {
-

Swaplace

+

Swaplace

-
+
Your greatest deals are here
-
+
Connect your wallet to start swapping your NFTs and tokens
@@ -23,7 +23,7 @@ export const CardHome = () => {
diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 17714bca..22e97f9d 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -3,8 +3,9 @@ import cc from "classcat"; import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useTheme } from "next-themes"; -import { ConnectWallet } from "@/components/01-atoms"; +import { ConnectWallet, SwappingIcons } from "@/components/01-atoms"; import { SwaplaceIcon, WalletIcon } from "@/components/01-atoms/icons/"; +import Link from "next/link"; export const TheHeader = () => { const { isDesktop } = useScreenSize(); @@ -28,15 +29,22 @@ export const TheHeader = () => { const currentTheme = theme === "system" ? systemTheme : theme; return ( -
- -
- +
+
+ + + +
+ +
+
+
+
-
+
{currentTheme === "dark" ? (
, )} ) : nftData.contract.name && nftData.id.tokenId ? ( @@ -138,7 +138,7 @@ export const NftCard = ({ {ButtonLayout(
{nftData.metadata?.name} -
+
, )} ) : null; diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 633b7d57..fdb47eae 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -38,7 +38,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { data ? data : new EthereumAddress( - validatedAddressToSwap + validatedAddressToSwap, ).getEllipsedAddress() } gives`}

diff --git a/components/02-molecules/SwapStation.tsx b/components/02-molecules/SwapStation.tsx index 1831bf6b..31e02d7c 100644 --- a/components/02-molecules/SwapStation.tsx +++ b/components/02-molecules/SwapStation.tsx @@ -13,7 +13,7 @@ export const SwapStation = () => { useEffect(() => { setIsValidSwap( - !!nftAuthUser.length && !!nftInputUser.length && !!validatedAddressToSwap + !!nftAuthUser.length && !!nftInputUser.length && !!validatedAddressToSwap, ); }, [nftAuthUser, nftInputUser, validatedAddressToSwap]); @@ -34,7 +34,7 @@ export const SwapStation = () => { if (!nftInputUser.length) { toast.error( - "You must select at least one NFT from the destiny wallet to swap" + "You must select at least one NFT from the destiny wallet to swap", ); return; } diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 22e97f9d..1c294e44 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -11,7 +11,7 @@ export const TheHeader = () => { const { isDesktop } = useScreenSize(); const { authenticatedUserAddress } = useAuthenticatedUser(); const [showFullNav, setShowFullNav] = useState( - !isDesktop && !!authenticatedUserAddress?.address + !isDesktop && !!authenticatedUserAddress?.address, ); useEffect(() => { diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index fcbda686..0afc15db 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -24,7 +24,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { const { chain } = useNetwork(); const [nftsList, setNftsList] = useState(); const [nftsQueryStatus, setNftsQueryStatus] = useState( - NFTsQueryStatus.EMPTY_QUERY + NFTsQueryStatus.EMPTY_QUERY, ); const { theme } = useTheme(); diff --git a/lib/client/blockchain-data.ts b/lib/client/blockchain-data.ts index cfa28081..b7ccfe3b 100644 --- a/lib/client/blockchain-data.ts +++ b/lib/client/blockchain-data.ts @@ -7,7 +7,7 @@ import { getTimestamp } from "./utils"; export const getNftsFrom = async ( address: string, chainId: number, - stateSetter: Dispatch> + stateSetter: Dispatch>, ) => { const baseUrl = getRpcHttpUrlForNetwork.get(chainId); @@ -52,12 +52,12 @@ export async function makeConfig( Contract: any, allowed: any, destinationChainSelector: any, - expiration: any + expiration: any, ) { const config = await Contract.packData( allowed, destinationChainSelector, - expiration + expiration, ); return config; } @@ -70,7 +70,7 @@ export async function makeSwap( expiration: any, biding: NFT[], asking: NFT[], - chainId: number + chainId: number, ) { const timestamp = await getTimestamp(chainId); if (expiration < timestamp) { @@ -85,7 +85,7 @@ export async function makeSwap( Contract, allowed, destinationChainSelector, - expiration + expiration, ); const swap: Swap = { diff --git a/lib/client/hooks/useAuthenticatedUser.tsx b/lib/client/hooks/useAuthenticatedUser.tsx index 8e12048c..bd86dbb5 100644 --- a/lib/client/hooks/useAuthenticatedUser.tsx +++ b/lib/client/hooks/useAuthenticatedUser.tsx @@ -67,7 +67,7 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { setAuthenticatedAccountAddress( accountAuthenticated && address ? new EthereumAddress(address.toLowerCase()) - : null + : null, ); setLoadingAuthenticatedUser(false); }, [nextAuthUser, isConnected, address]); diff --git a/lib/client/hooks/useScreenSize.tsx b/lib/client/hooks/useScreenSize.tsx index f9342b6c..f4b1785c 100644 --- a/lib/client/hooks/useScreenSize.tsx +++ b/lib/client/hooks/useScreenSize.tsx @@ -13,16 +13,16 @@ export const useScreenSize = () => { const checkIfIsMobile = () => { setIsMobile( - window.matchMedia(`(max-width: ${TABLET_SCREEN_SIZE - 1}px)`).matches + window.matchMedia(`(max-width: ${TABLET_SCREEN_SIZE - 1}px)`).matches, ); setIsTablet( - window.matchMedia(`(max-width: ${DESKTOP_SCREEN_SIZE - 1}px)`).matches + window.matchMedia(`(max-width: ${DESKTOP_SCREEN_SIZE - 1}px)`).matches, ); setIsDesktop( - window.matchMedia(`(min-width: ${DESKTOP_SCREEN_SIZE}px)`).matches + window.matchMedia(`(min-width: ${DESKTOP_SCREEN_SIZE}px)`).matches, ); setIsWideScreen( - window.matchMedia(`(min-width: ${WIDE_SCREEN_SIZE}px)`).matches + window.matchMedia(`(min-width: ${WIDE_SCREEN_SIZE}px)`).matches, ); }; diff --git a/lib/shared/types.ts b/lib/shared/types.ts index 5deb5b2e..609c4681 100644 --- a/lib/shared/types.ts +++ b/lib/shared/types.ts @@ -1,7 +1,7 @@ export class EthereumAddress { static readonly ETHEREUM_ADDRESS_LENGTH = 40; static readonly pattern = new RegExp( - `^0x[a-fA-F0-9]{${EthereumAddress.ETHEREUM_ADDRESS_LENGTH}}$` + `^0x[a-fA-F0-9]{${EthereumAddress.ETHEREUM_ADDRESS_LENGTH}}$`, ); private readonly _value: string; diff --git a/lib/wallet/wallet-config.ts b/lib/wallet/wallet-config.ts index 760b9042..3088e022 100644 --- a/lib/wallet/wallet-config.ts +++ b/lib/wallet/wallet-config.ts @@ -20,7 +20,7 @@ export const { chains, webSocketPublicClient, publicClient } = configureChains( http: getRpcHttpUrlForNetwork.get(chain.id) ?? "", }), }), - ] + ], ); const connectorArgs = { From d1aeb6874f959002325acedee7d9f26e168d12d6 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 19 Dec 2023 17:09:38 -0300 Subject: [PATCH 006/305] feat: add CONTRIBUTING.MD --- CONTRIBUTING.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..30a5b284 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contribution Guidelines + +Thank you for your interest in contributing to Swaplace! The project is an open source build by the community. We are welcome any type of contribution, suggestion or improvement, no matter how small. + +### Contents + +- [Open Source Guideline](#how-to-contribute) +- [Opening an Issue](#opening-issue) +- [Writing Commit Messages](#writing-commit-messages) +- [Submitting Pull Requests](#submiting-pull-requests) +- [Code Review](#code-review) +- [Coding Style](#coding-style) +- [Get in touch](#get-in-touch) + +## How to Contribute + +There are many ways to contribute, but here are a few steps to start: + +1. Fork the repository in GitHub +2. Check if you have any issue, suggestion or improvement to work in. + + - We manage all the issues using [GitHub Projects](https://github.com/orgs/blockful-io/projects/3) + +3. Send a message in the issue like + `I'm interested in this issue` or ask for more information like `Hey, can you provide more information about this ... ?`and the mantainers will assigned or provide more context about your issue. **After that, you are asigned to the issue.** + +4. If a task is already assigned but you believe you can expedite the process, feel free to comment, requesting to assist or speed up the task. Additionally, you may open a pull request directly because we prioritize both code efficiency and delivery speed. Thus, we encourage multiple individuals to review the same issues and debate together to enhance the code's security. + +### Congratulations ! Now you can start work in the issue and everyone knows you are assigned. + +## Opening Issue + +Before opening an issue, please check if there is no issue open. If there is, feel free to comment or suggest more details. We are always open to feedback and receptive to suggestions! + +- Before [creating an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-an-issue#creating-an-issue-from-a-project), check if your fork is updated. + +## Writing Commit Messages + +We are using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) + +Some examples below: + +- feat: adds or remove a new feature +- fix: fixes a bug +- refactor: rewrite/restructure your code +- chore: changes to the build process or auxiliary tools and libraries such as documentation generation +- style: changes do not affect the meaning (white-space, formatting, missing semi-colons, etc) +- test: add missing tests or correcting existing tests +- docs: affect documentation only + +## Submiting Pull Requests + +You can resolve an issue and after that submit a pull request fixing an issue and remember to [reference that issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword#linking-a-pull-request-to-an-issue-using-a-keyword). When submit a PR, put the code below with the number of the issue you are closing +`Example: closes #1` + +## Code Review + +The maintainers will review your PR. If something is missing or a fix needs to be made, the maintainers will let you know in the PR comment. + +## Coding Style + +In Swaplace please use this .prettierrc.yml configuration to make the code standardized. + +``` +{ + trailingComma: "all" + singleQuote: false + printWidth: 80 + tabWidth: 2 + semi: true +} +``` + +## Get in Touch + +If you need to get in contact with the repository maintainers, please reach out in our [Discord](https://discord.gg/B6uDmm7hvC). From 06430297d975cea37ec8b688da6855c345966bd8 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 20 Dec 2023 15:05:56 -0300 Subject: [PATCH 007/305] feat: add empty-cards add empty cards in offer-sumary & nfts-list --- components/02-molecules/NftCard.tsx | 2 +- components/02-molecules/NftsList.tsx | 47 ++++++++--- components/02-molecules/OfferSummary.tsx | 56 ++++++++++---- components/02-molecules/SwapStation.tsx | 2 +- components/03-organisms/NftsShelf.tsx | 90 +++++++++++----------- components/03-organisms/SwappingShelfs.tsx | 7 ++ components/04-templates/SwapSection.tsx | 2 +- lib/client/constants.ts | 5 ++ styles/global.css | 4 + 9 files changed, 142 insertions(+), 73 deletions(-) diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index 37db1cbd..897a81da 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -100,7 +100,7 @@ export const NftCard = ({ diff --git a/components/01-atoms/EmptyNftsCards.tsx b/components/01-atoms/EmptyNftsCards.tsx new file mode 100644 index 00000000..788d2736 --- /dev/null +++ b/components/01-atoms/EmptyNftsCards.tsx @@ -0,0 +1,31 @@ +import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; + +export const EmptyNftsCards = ( + len: number, + ismobileTotalSquares: number, + isWideScreenTotalSquares: number, + isDesktopTotalSquares: number, + isTabletTotalSquares: number, +) => { + const { isDesktop, isTablet, isWideScreen, isMobile } = useScreenSize(); + + let totalSquares: number = 0; + + isMobile + ? (totalSquares = ismobileTotalSquares) + : isWideScreen + ? (totalSquares = isWideScreenTotalSquares) + : isDesktop + ? (totalSquares = isDesktopTotalSquares) + : isTablet && (totalSquares = isTabletTotalSquares); + + const emptySquaresCount = Math.max(totalSquares - len, 0); + + const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( + <> +
+ + )); + + return emptySquares; +}; diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index 4a3f8675..8fd70de2 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -19,6 +19,8 @@ interface SwapContextProps { nftInputUser: NFT[]; destinyChain: SupportedNetworks; setDestinyChain: Dispatch>; + setTimeDate: Dispatch>; + timeDate: bigint; } export const SwapContext = React.createContext({ @@ -37,6 +39,8 @@ export const SwapContext = React.createContext({ nftInputUser: [], destinyChain: SupportedNetworks.SEPOLIA, setDestinyChain: () => {}, + setTimeDate: () => {}, + timeDate: BigInt(1), }); export const SwapContextProvider = ({ children }: any) => { @@ -48,6 +52,7 @@ export const SwapContextProvider = ({ children }: any) => { const [destinyChain, setDestinyChain] = useState( SupportedNetworks.SEPOLIA, ); + const [timeDate, setTimeDate] = useState(BigInt(1)); const validateAddressToSwap = ( _authedUser: EthereumAddress, @@ -121,6 +126,8 @@ export const SwapContextProvider = ({ children }: any) => { nftInputUser, destinyChain, setDestinyChain, + setTimeDate, + timeDate, }); }, [ inputAddress, @@ -129,6 +136,7 @@ export const SwapContextProvider = ({ children }: any) => { nftAuthUser, nftInputUser, destinyChain, + timeDate, ]); const [swapData, setSwapData] = useState({ @@ -144,6 +152,8 @@ export const SwapContextProvider = ({ children }: any) => { nftInputUser, destinyChain, setDestinyChain, + setTimeDate, + timeDate, }); return ( diff --git a/components/01-atoms/SwapExpireTime.tsx b/components/01-atoms/SwapExpireTime.tsx new file mode 100644 index 00000000..915a30b9 --- /dev/null +++ b/components/01-atoms/SwapExpireTime.tsx @@ -0,0 +1,68 @@ +import React, { useContext, useEffect, useState } from "react"; +import { useNetwork } from "wagmi"; +import { SwapContext } from "."; +import { TimeStampDate, ExpireDate } from "@/lib/client/constants"; +import { getTimestamp } from "@/lib/client/utils"; + +export const SwapExpireTime = () => { + const { chain } = useNetwork(); + const { setTimeDate } = useContext(SwapContext); + const [selectedOption, setSelectedOption] = useState( + TimeStampDate.ONE_DAY, + ); + + let chainID: number; + + if (typeof chain?.id !== "undefined") { + chainID = chain.id; + } + + const fetchData = async (selectedValue: TimeStampDate) => { + try { + const timeSelected = BigInt(selectedValue); + const timestamp = await getTimestamp(chainID); + setTimeDate(timeSelected + timestamp); + } catch (error) { + console.error("error", error); + } + }; + + const handleSelectChange = (event: React.ChangeEvent) => { + const selectedValue = event.target.value as unknown as TimeStampDate; + setSelectedOption(selectedValue); + fetchData(selectedValue); + }; + + useEffect(() => { + fetchData(selectedOption); + }, [selectedOption]); + + return ( +
+
+
+ Expires in +
+
+
+ +
+
+
+
+ ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index dd21187c..d7356e82 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -1,4 +1,5 @@ export * from "./ConnectWallet"; +export * from "./EmptyNftsCards"; export * from "./StatusOffers"; export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; @@ -7,5 +8,6 @@ export * from "./ConfirmSwapModal"; export * from "./TransactionResultModal"; export * from "./LoadingIndicator"; export * from "./SwapContext"; +export * from "./SwapExpireTime"; export * from "./SwappingIcons"; export * from "./Tab"; diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index e29334c6..1c2e6e99 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -1,6 +1,6 @@ import { INftsList, NFT } from "@/lib/client/constants"; import { NftCard } from "@/components/02-molecules"; -import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; +import { EmptyNftsCards } from "@/components/01-atoms"; /** * @@ -12,7 +12,7 @@ import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; */ export const NftsList = ({ nftsList, ownerAddress }: INftsList) => { - const emptySquares = EmptyNftsCards(nftsList.length); + const emptySquares = EmptyNftsCards(nftsList.length, 15, 30, 30, 30); const nftSquares = nftsList.map((nft: NFT, index) => (
@@ -27,27 +27,3 @@ export const NftsList = ({ nftsList, ownerAddress }: INftsList) => {
); }; - -const EmptyNftsCards = (len: number) => { - const { isDesktop, isTablet, isWideScreen, isMobile } = useScreenSize(); - - let totalSquares: number = 0; - - isMobile - ? (totalSquares = 15) - : isWideScreen - ? (totalSquares = 30) - : isDesktop - ? (totalSquares = 30) - : isTablet && (totalSquares = 30); - - const emptySquaresCount = Math.max(totalSquares - len, 0); - - const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( - <> -
- - )); - - return emptySquares; -}; diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 0f53eb09..af7e8582 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -6,7 +6,7 @@ import { ChainInfo } from "@/lib/client/constants"; import { SwapContext } from "@/components/01-atoms"; import { PersonIcon } from "@/components/01-atoms/icons"; import { NftCard } from "@/components/02-molecules"; -import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; +import { EmptyNftsCards } from "@/components/01-atoms"; interface IOfferSummary { forAuthedUser: boolean; @@ -21,8 +21,14 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { }); const { authenticatedUserAddress } = useAuthenticatedUser(); - const emptySquaresAuthUser = EmptyNftsCards(nftAuthUser.length); - const emptySquaresInputUser = EmptyNftsCards(nftInputUser.length); + const emptySquaresAuthUser = EmptyNftsCards(nftAuthUser.length, 4, 8, 12, 12); + const emptySquaresInputUser = EmptyNftsCards( + nftInputUser.length, + 4, + 8, + 12, + 12, + ); return (
@@ -97,26 +103,3 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {
); }; - -const EmptyNftsCards = (len: number) => { - const { isDesktop, isTablet, isWideScreen, isMobile } = useScreenSize(); - - let totalSquares: number = 0; - isMobile - ? (totalSquares = 4) - : isWideScreen - ? (totalSquares = 8) - : isDesktop - ? (totalSquares = 12) - : isTablet && (totalSquares = 12); - - const emptySquaresCount = Math.max(totalSquares - len, 0); - - const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( - <> -
- - )); - - return emptySquares; -}; diff --git a/components/02-molecules/SwapStation.tsx b/components/02-molecules/SwapStation.tsx index 50524e4b..24e95a52 100644 --- a/components/02-molecules/SwapStation.tsx +++ b/components/02-molecules/SwapStation.tsx @@ -4,6 +4,7 @@ import { PaperPlane } from "@/components/01-atoms/icons"; import { OfferSummary } from "@/components/02-molecules"; import cc from "classcat"; import toast from "react-hot-toast"; +import { SwapExpireTime } from "@/components/01-atoms/SwapExpireTime"; export const SwapStation = () => { const [isValidSwap, setIsValidSwap] = useState(false); @@ -46,9 +47,16 @@ export const SwapStation = () => { return (
-

- Swap offer -

+
+
+

+ Swap offer +

+
+
+ +
+
diff --git a/lib/client/abi.ts b/lib/client/abi.ts new file mode 100644 index 00000000..7793a71c --- /dev/null +++ b/lib/client/abi.ts @@ -0,0 +1,446 @@ +export const SwaplaceAbi = [ + { + inputs: [ + { + internalType: "address", + name: "caller", + type: "address", + }, + ], + name: "InvalidAddress", + type: "error", + }, + { + inputs: [], + name: "InvalidAssetsLength", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "timestamp", + type: "uint256", + }, + ], + name: "InvalidExpiry", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "acceptee", + type: "address", + }, + ], + name: "SwapAccepted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "SwapCanceled", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + ], + name: "SwapCreated", + type: "event", + }, + { + inputs: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "acceptSwap", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "cancelSwap", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "allowed", + type: "address", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "biding", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "asking", + type: "tuple[]", + }, + ], + internalType: "struct ISwap.Swap", + name: "swap", + type: "tuple", + }, + ], + name: "createSwap", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "getSwap", + outputs: [ + { + components: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "allowed", + type: "address", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "biding", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "asking", + type: "tuple[]", + }, + ], + internalType: "struct ISwap.Swap", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + name: "makeAsset", + outputs: [ + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset", + name: "", + type: "tuple", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "allowed", + type: "address", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "biding", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "asking", + type: "tuple[]", + }, + ], + name: "makeSwap", + outputs: [ + { + components: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "allowed", + type: "address", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "biding", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + { + internalType: "uint256", + name: "amountOrId", + type: "uint256", + }, + ], + internalType: "struct ISwap.Asset[]", + name: "asking", + type: "tuple[]", + }, + ], + internalType: "struct ISwap.Swap", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes4", + name: "interfaceID", + type: "bytes4", + }, + ], + name: "supportsInterface", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "totalSwaps", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/lib/client/blockchain-data.ts b/lib/client/blockchain-data.ts index b7ccfe3b..1e7167a8 100644 --- a/lib/client/blockchain-data.ts +++ b/lib/client/blockchain-data.ts @@ -1,9 +1,17 @@ -import { ethers } from "ethers"; import { Dispatch, SetStateAction } from "react"; import { NFT, NFTsQueryStatus, getRpcHttpUrlForNetwork } from "./constants"; -import { publicClient } from "../wallet/wallet-config"; import { getTimestamp } from "./utils"; +export interface Swapping { + walletClient: any; + expireDate: bigint; + nftInputUser: any; + nftAuthUser: any; + validatedAddressToSwap: string; + authenticatedUserAddress: any; + chain: number; +} + export const getNftsFrom = async ( address: string, chainId: number, diff --git a/lib/client/constants.ts b/lib/client/constants.ts index 2d4d2778..7ffff4bf 100644 --- a/lib/client/constants.ts +++ b/lib/client/constants.ts @@ -26,6 +26,7 @@ export enum NFTsQueryStatus { export enum SupportedNetworks { SEPOLIA = "SEPOLIA", MUMBAI = "MUMBAI", + HARDHAT = "HARDHAT", } interface ChainProps { @@ -42,14 +43,47 @@ export const ChainInfo: Record = { id: 80001, name: "Polygon Mumbai", }, + [SupportedNetworks.HARDHAT]: { + id: 31337, + name: "Hardhat", + }, }; export let getRpcHttpUrlForNetwork: Map = new Map([ [ChainInfo.SEPOLIA.id, process.env.NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP ?? ""], [ChainInfo.MUMBAI.id, process.env.NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP ?? ""], + [ChainInfo.HARDHAT.id, "http://127.0.0.1:8545/"], ]); export const SWAPLACE_SMART_CONTRACT_ADDRESS = { - [ChainInfo.SEPOLIA.id]: "0xcB003ed4Df4679D15b8863BB8F7609855A6a380d", + [ChainInfo.HARDHAT.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.SEPOLIA.id]: "0xD8E3580C1b6f117c5b35DdD01dd9e50d9487501D", [ChainInfo.MUMBAI.id]: "0xcB003ed4Df4679D15b8863BB8F7609855A6a380d", }; + +export enum TimeStampDate { + ONE_DAY = 24 * 60 * 60 * 1000, + ONE_WEEK = ONE_DAY * 7, + ONE_MONTH = ONE_WEEK * 4, + SIX_MONTH = ONE_MONTH * 6, + ONE_YEAR = SIX_MONTH * 2, +} + +export const ONE_DAY = 24 * 60 * 60 * 1000; +export const ONE_WEEK = ONE_DAY * 7; +export const ONE_MONTH = ONE_WEEK * 4; +export const SIX_MONTH = ONE_MONTH * 6; +export const ONE_YEAR = SIX_MONTH * 2; + +export interface ExpireOption { + label: string; + value: TimeStampDate; +} + +export const ExpireDate: ExpireOption[] = [ + { label: "1 Day", value: ONE_DAY }, + { label: "7 Days", value: ONE_WEEK }, + { label: "1 Month", value: ONE_MONTH }, + { label: "6 Month", value: SIX_MONTH }, + { label: "1 Year", value: ONE_YEAR }, +]; diff --git a/lib/client/utils.ts b/lib/client/utils.ts index e1248827..83664f16 100644 --- a/lib/client/utils.ts +++ b/lib/client/utils.ts @@ -19,4 +19,5 @@ export const getTimestamp = async (chainId: number) => { const blockDetails = await provider.getBlock({ blockNumber: block }); const timestamp = blockDetails.timestamp; + return timestamp; }; diff --git a/lib/service/creatingSwap.ts b/lib/service/creatingSwap.ts new file mode 100644 index 00000000..f199c4f6 --- /dev/null +++ b/lib/service/creatingSwap.ts @@ -0,0 +1,39 @@ +import { SwaplaceAbi } from "../client/abi"; +import { Swapping } from "../client/blockchain-data"; +import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "../client/constants"; +import { hexToNumber } from "viem"; + +export function creatingSwap({ + walletClient, + expireDate, + nftInputUser, + nftAuthUser, + validatedAddressToSwap, + authenticatedUserAddress, + chain, +}: Swapping) { + return walletClient?.writeContract({ + abi: SwaplaceAbi, + functionName: "createSwap", + args: [ + { + owner: authenticatedUserAddress.address as `0x${string}`, + allowed: validatedAddressToSwap as `0x${string}`, + expiry: expireDate, + biding: [ + { + addr: nftAuthUser.contract.address, + amountOrId: hexToNumber(nftAuthUser.id.tokenId), + }, + ], + asking: [ + { + addr: nftInputUser.contract.address, + amountOrId: hexToNumber(nftInputUser.id.tokenId), + }, + ], + }, + ], + address: SWAPLACE_SMART_CONTRACT_ADDRESS[chain] as `0x${string}`, + }); +} diff --git a/lib/wallet/wallet-config.ts b/lib/wallet/wallet-config.ts index 3088e022..351273e9 100644 --- a/lib/wallet/wallet-config.ts +++ b/lib/wallet/wallet-config.ts @@ -1,4 +1,4 @@ -import { polygonMumbai, sepolia } from "@wagmi/core/chains"; +import { polygonMumbai, sepolia, hardhat } from "@wagmi/core/chains"; import { configureChains, createConfig } from "wagmi"; import { trustWallet, @@ -13,7 +13,7 @@ import { jsonRpcProvider } from "wagmi/providers/jsonRpc"; import { getRpcHttpUrlForNetwork } from "../client/constants"; export const { chains, webSocketPublicClient, publicClient } = configureChains( - [sepolia, polygonMumbai], + [sepolia, polygonMumbai, hardhat], [ jsonRpcProvider({ rpc: (chain) => ({ @@ -25,7 +25,7 @@ export const { chains, webSocketPublicClient, publicClient } = configureChains( const connectorArgs = { appName: "Swaplace dApp", - chains: [sepolia, polygonMumbai], + chains: [sepolia, polygonMumbai, hardhat], projectId: process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID ?? "", }; From 5ddcdd56aa11098c9c30213ca6bf301368e32b8f Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 27 Dec 2023 18:46:59 -0300 Subject: [PATCH 010/305] feat: add create-swap-n-n - refactor frontend v1 - remove chains ids - adjust the select time - add create swap n-n - adjust design --- components/01-atoms/ConfirmSwapModal.tsx | 17 ++-- components/01-atoms/SearchBar.tsx | 21 +---- components/01-atoms/SwapExpireTime.tsx | 6 +- components/02-molecules/NftCard.tsx | 60 ++++++++------ components/02-molecules/OfferSummary.tsx | 49 +++++------- lib/client/abi.ts | 33 ++++++-- lib/client/blockchain-data.ts | 39 +++++++++- lib/service/creatingSwap.ts | 99 +++++++++++++++++++----- lib/wallet/wallet-config.ts | 6 ++ styles/global.css | 2 +- 10 files changed, 223 insertions(+), 109 deletions(-) diff --git a/components/01-atoms/ConfirmSwapModal.tsx b/components/01-atoms/ConfirmSwapModal.tsx index aee4b747..471c0dac 100644 --- a/components/01-atoms/ConfirmSwapModal.tsx +++ b/components/01-atoms/ConfirmSwapModal.tsx @@ -6,7 +6,7 @@ import { SwapContext, TransactionResultModal } from "@/components/01-atoms"; import { NftCard, NftCardActionType } from "@/components/02-molecules"; import { SwapIcon } from "@/components/01-atoms/icons"; import { creatingSwap } from "@/lib/service/creatingSwap"; -import { Swapping } from "@/lib/client/blockchain-data"; +import { ComposeNftSwap, ICreateSwap } from "@/lib/client/blockchain-data"; interface ConfirmSwapModalProps { open: boolean; @@ -49,23 +49,30 @@ export const ConfirmSwapModal = ({ open, onClose }: ConfirmSwapModalProps) => { return null; } + const nftsInputUser = ComposeNftSwap(nftInputUser); + const nftsAuthUser = ComposeNftSwap(nftAuthUser); + let chainId: number; const handleOffer = () => { if (typeof chain?.id != "undefined") { chainId = chain?.id; } - const swapData: Swapping = { + const swapData: ICreateSwap = { walletClient: walletClient, expireDate: timeDate, - nftInputUser: nftInputUser[0], - nftAuthUser: nftAuthUser[0], + nftInputUser: nftsInputUser, + nftAuthUser: nftsAuthUser, validatedAddressToSwap: validatedAddressToSwap, authenticatedUserAddress: authenticatedUserAddress, chain: chainId, }; - return creatingSwap(swapData); + try { + creatingSwap(swapData); + } catch (error) { + console.error(error); + } }; return ( diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 94e65c45..2e8f33a0 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -1,11 +1,7 @@ import cc from "classcat"; import { useContext, useEffect, useState } from "react"; import { MagnifyingGlassIcon } from "@/components/01-atoms/icons"; -import { - SelectAuthedUserChain, - SelectDestinyChain, - SwapContext, -} from "@/components/01-atoms"; +import { SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { ENS } from "web3-eth-ens"; import Web3 from "web3"; @@ -131,21 +127,6 @@ export const SearchBar = () => {
- -
-
-

Your network:

- -
-
-

- Searched address network: -

-
- -
-
-
); }; diff --git a/components/01-atoms/SwapExpireTime.tsx b/components/01-atoms/SwapExpireTime.tsx index 915a30b9..65949cb9 100644 --- a/components/01-atoms/SwapExpireTime.tsx +++ b/components/01-atoms/SwapExpireTime.tsx @@ -40,7 +40,7 @@ export const SwapExpireTime = () => { return (
-
+
Expires in
@@ -48,13 +48,13 @@ export const SwapExpireTime = () => { +
+
+
+ +
+
+ ); +}; + +const TokenBody = () => { + enum TokenPosibilities { + ERC20 = "ERC20", + ERC721 = "ERC721", + } + + type TokenPossibilites = TokenPosibilities | "ERC20" | "ERC721"; + + const [token, setToken] = useState("ERC20"); + return ( +
+
+
What kind of token you want to add?
+
+ + +
+
+
+ {token === "ERC20" ? ( +
+
Contract address
+
+ +
+
+ ) : ( +
+
+
Contract address
+
+ +
+
+
+
Token ID
+
+ +
+
+
+ )} +
+
+ +
+
+ ); +}; + +const AddManuallyVariantConfig: Record = + { + [AddManuallyVariant.SWAP]: { + header: "Add swap manually", + body: , + }, + [AddManuallyVariant.TOKEN]: { + header: "Add token", + body: , + }, + }; + +export const SwapAddManuallyModalLayout = ({ + variant = AddManuallyVariant.TOKEN, +}: AddManuallyProps) => { + const [openModal, setOpenModal] = useState(false); + const { theme } = useTheme(); + return ( +
+
+
+ {AddManuallyVariantConfig[variant].header} +
+
{ + setOpenModal(!openModal); + }} + > + +
+
+
{AddManuallyVariantConfig[variant].body}
+
+ ); +}; diff --git a/components/01-atoms/SwapModalLayout.tsx b/components/01-atoms/SwapModalLayout.tsx index 7592c7fa..9109ec35 100644 --- a/components/01-atoms/SwapModalLayout.tsx +++ b/components/01-atoms/SwapModalLayout.tsx @@ -76,11 +76,7 @@ export const SwapModalLayout = ({

{text.title}

-
+
diff --git a/components/01-atoms/icons/CloseIcon.tsx b/components/01-atoms/icons/CloseIcon.tsx index b8570295..ae0f93a2 100644 --- a/components/01-atoms/icons/CloseIcon.tsx +++ b/components/01-atoms/icons/CloseIcon.tsx @@ -2,21 +2,23 @@ import { SVGProps } from "react"; export const CloseIcon = (props: SVGProps) => { return ( - - - - - +
+ + + + + +
); }; diff --git a/styles/global.css b/styles/global.css index 292f3620..9bda1c48 100644 --- a/styles/global.css +++ b/styles/global.css @@ -15,6 +15,13 @@ input[type="search"]::-webkit-search-results-decoration { @tailwind utilities; @layer utilities { + .shadow-add-manually-card { + box-shadow: 0px 0px 12px 1px #00000066; + } + .shadow-add-manually-button { + box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.3); + } + .title-h1 { } @@ -65,6 +72,9 @@ input[type="search"]::-webkit-search-results-decoration { @apply font-onest font-medium text-[16px] leading-[20px] text-[#F6F6F6]; } + .p-medium-bold-variant-black { + @apply font-onest font-medium text-[14px] leading-[16px] text-[#181A19]; + } .p-medium-bold { @apply font-onest font-medium text-[14px] leading-[16px] text-[#707572]; } From 70dbcb8c423a482ff2cc681d78f01456da43b074 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 15 Feb 2024 14:22:11 -0300 Subject: [PATCH 061/305] feat: add open&close & resize to mobile devices --- .../01-atoms/SwapAddManuallyModalLayout.tsx | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/components/01-atoms/SwapAddManuallyModalLayout.tsx b/components/01-atoms/SwapAddManuallyModalLayout.tsx index 39e628df..36428da1 100644 --- a/components/01-atoms/SwapAddManuallyModalLayout.tsx +++ b/components/01-atoms/SwapAddManuallyModalLayout.tsx @@ -1,4 +1,5 @@ import { CloseIcon } from "./icons/CloseIcon"; +import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import React, { useState } from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; @@ -17,6 +18,8 @@ interface AddManuallyConfig { interface AddManuallyProps { variant?: Variant; + open: boolean; + onClose: () => void; } const SwapBody = () => { @@ -127,26 +130,31 @@ const AddManuallyVariantConfig: Record = export const SwapAddManuallyModalLayout = ({ variant = AddManuallyVariant.TOKEN, + open, + onClose, }: AddManuallyProps) => { - const [openModal, setOpenModal] = useState(false); const { theme } = useTheme(); + const { isMobile } = useScreenSize(); return ( -
-
-
- {AddManuallyVariantConfig[variant].header} -
+ <> + {open && (
{ - setOpenModal(!openModal); - }} + className={cc([ + "dark:bg-[#212322] min-h-[256px] min-w-[400px] border rounded-[20px] border-[#353836] shadow-add-manually-card", + isMobile && "min-w-[90%] w-[300px]", + ])} > - +
+
+ {AddManuallyVariantConfig[variant].header} +
+
+ +
+
+
{AddManuallyVariantConfig[variant].body}
-
-
{AddManuallyVariantConfig[variant].body}
-
+ )} + ); }; From c3d5ca10604eae1544af27d008493090f5e55a7d Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 15 Feb 2024 15:32:53 -0300 Subject: [PATCH 062/305] feat: add light/dark mode in component --- .../01-atoms/SwapAddManuallyModalLayout.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/01-atoms/SwapAddManuallyModalLayout.tsx b/components/01-atoms/SwapAddManuallyModalLayout.tsx index 36428da1..5ef906dc 100644 --- a/components/01-atoms/SwapAddManuallyModalLayout.tsx +++ b/components/01-atoms/SwapAddManuallyModalLayout.tsx @@ -28,7 +28,7 @@ const SwapBody = () => {
Swap ID
- +
@@ -56,10 +56,10 @@ const TokenBody = () => {
From a0e010cc47f699d2911c5741bed7c1fdc739d50d Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 15 Feb 2024 16:50:58 -0300 Subject: [PATCH 063/305] feat:add background opacity when open dialog --- .../01-atoms/SwapAddManuallyModalLayout.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/01-atoms/SwapAddManuallyModalLayout.tsx b/components/01-atoms/SwapAddManuallyModalLayout.tsx index 5ef906dc..3fb53d47 100644 --- a/components/01-atoms/SwapAddManuallyModalLayout.tsx +++ b/components/01-atoms/SwapAddManuallyModalLayout.tsx @@ -136,11 +136,16 @@ export const SwapAddManuallyModalLayout = ({ const { theme } = useTheme(); const { isMobile } = useScreenSize(); return ( - <> - {open && ( + +
@@ -154,7 +159,7 @@ export const SwapAddManuallyModalLayout = ({
{AddManuallyVariantConfig[variant].body}
- )} - +
+ ); }; From e182315eca2fbb6918b44fd58ecec544d7f5a227 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 15 Feb 2024 17:03:38 -0300 Subject: [PATCH 064/305] update: text color in light mode --- components/01-atoms/SwapAddManuallyModalLayout.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/components/01-atoms/SwapAddManuallyModalLayout.tsx b/components/01-atoms/SwapAddManuallyModalLayout.tsx index 3fb53d47..16507d5a 100644 --- a/components/01-atoms/SwapAddManuallyModalLayout.tsx +++ b/components/01-atoms/SwapAddManuallyModalLayout.tsx @@ -26,7 +26,7 @@ const SwapBody = () => { return (
-
Swap ID
+
Swap ID
@@ -85,7 +85,9 @@ const TokenBody = () => {
{token === "ERC20" ? (
-
Contract address
+
+ Contract address +
@@ -93,13 +95,17 @@ const TokenBody = () => { ) : (
-
Contract address
+
+ Contract address +
-
Token ID
+
+ Token ID +
From 485ff6355e6e17412ae225b86dce191ace8e48a6 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 15 Feb 2024 17:05:37 -0300 Subject: [PATCH 065/305] update: globals css --- styles/global.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/styles/global.css b/styles/global.css index 9bda1c48..c08b39e7 100644 --- a/styles/global.css +++ b/styles/global.css @@ -89,6 +89,9 @@ input[type="search"]::-webkit-search-results-decoration { @apply font-onest font-medium text-[14px] leading-[20px] text-[#F6F6F6]; } + .p-small-variant-black { + @apply font-onest font-normal text-[14px] leading-[20px] text-[#181A19]; + } .p-small { @apply font-onest font-normal text-[14px] leading-[20px] text-[#707572]; } From f3a7023680a0b8e599717f8ca5f2bcb6ea08c3e9 Mon Sep 17 00:00:00 2001 From: eduramme Date: Thu, 15 Feb 2024 17:15:10 -0300 Subject: [PATCH 066/305] fix header --- components/01-atoms/ConnectWallet.tsx | 2 +- components/01-atoms/SwappingIcons.tsx | 30 +++++------ components/02-molecules/TheHeader.tsx | 2 +- package-lock.json | 72 ++++++++++++++++++--------- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/components/01-atoms/ConnectWallet.tsx b/components/01-atoms/ConnectWallet.tsx index 1bb47c30..677e6485 100644 --- a/components/01-atoms/ConnectWallet.tsx +++ b/components/01-atoms/ConnectWallet.tsx @@ -1,6 +1,6 @@ +import { WalletIcon } from "./icons"; import { ConnectButton } from "@rainbow-me/rainbowkit"; import { useRouter } from "next/router"; -import { WalletIcon } from "./icons"; interface IConnectWallet { customStyle?: string; diff --git a/components/01-atoms/SwappingIcons.tsx b/components/01-atoms/SwappingIcons.tsx index b015bca8..e9c3a2b9 100644 --- a/components/01-atoms/SwappingIcons.tsx +++ b/components/01-atoms/SwappingIcons.tsx @@ -86,52 +86,52 @@ export const SwappingIcons = () => { }; return ( -
- {swappingTabs.map((swapIcons) => { + <> + {swappingTabs.map((swapIcon) => { return ( - <> +
{isWideScreen ? ( - +
{ - handleClick(swapIcons); + handleClick(swapIcon); }} >
- {swapIcons.icon} + {swapIcon.icon}
) : ( - +
{ - handleClick(swapIcons); + handleClick(swapIcon); }} >
- {swapIcons.icon} + {swapIcon.icon}
)} - + ); })} -
+ ); }; diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 4e433aad..40a2b808 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -6,7 +6,7 @@ import { SwappingIcons, Tooltip, } from "@/components/01-atoms"; -import { SwaplaceIcon, WalletIcon } from "@/components/01-atoms/icons/"; +import { SwaplaceIcon } from "@/components/01-atoms/icons/"; import { useTheme } from "next-themes"; import React, { useEffect, useState } from "react"; import Link from "next/link"; diff --git a/package-lock.json b/package-lock.json index 33885b94..1fe38235 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@rainbow-me/rainbowkit": "^1.3.0", "@rainbow-me/rainbowkit-siwe-next-auth": "0.1.8", "@typescript-eslint/eslint-plugin": "5.54.1", - "addreth": "^1.2.0", + "axios": "^1.6.7", "boring-avatars": "1.7.0", "classcat": "^5.0.4", "eslint-plugin-unused-imports": "2.0.0", @@ -37,6 +37,7 @@ "@types/react-dom": "^18", "@typescript-eslint/parser": "^6.13.1", "autoprefixer": "^10.0.1", + "dotenv": "^16.4.1", "eslint": "^8", "eslint-config-next": "14.0.3", "postcss": "^8", @@ -3256,21 +3257,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/addreth": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/addreth/-/addreth-1.2.0.tgz", - "integrity": "sha512-LwO7aIqE+yEK6o6sCqyjRiJoRL4JZEAb3AuC5pAK6GvCXlpR+YziE2vaHshs/62MhNqB/q39/VDbXTgKF/pP6A==", - "peerDependencies": { - "react": ">=18.0.0", - "react-dom": ">=18.0.0", - "wagmi": ">=1.4.0" - }, - "peerDependenciesMeta": { - "wagmi": { - "optional": true - } - } - }, "node_modules/aes-js": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", @@ -3529,8 +3515,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/atomic-sleep": { "version": "1.0.0", @@ -3597,6 +3582,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -4008,7 +4003,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4231,7 +4225,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -4319,6 +4312,18 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.4.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.4.tgz", + "integrity": "sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -5339,6 +5344,25 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -5351,7 +5375,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6805,7 +6828,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -6814,7 +6836,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7756,6 +7777,11 @@ "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.5.1.tgz", "integrity": "sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", From 71901d0c3e4b98d7960907a4c053d35e463599ff Mon Sep 17 00:00:00 2001 From: eduramme Date: Thu, 15 Feb 2024 17:16:37 -0300 Subject: [PATCH 067/305] fix icon errors --- components/01-atoms/icons/SelectUserIcon.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/01-atoms/icons/SelectUserIcon.tsx b/components/01-atoms/icons/SelectUserIcon.tsx index 135b3cff..73677def 100644 --- a/components/01-atoms/icons/SelectUserIcon.tsx +++ b/components/01-atoms/icons/SelectUserIcon.tsx @@ -14,9 +14,9 @@ export const SelectUserIcon = (props: SVGProps) => { id="Vector" d="M31.0187 35L34.023 38M15.997 38H5.18143C4.05971 38 3.49884 38 3.0704 37.782C2.69354 37.5902 2.38714 37.2844 2.1951 36.908C1.97681 36.4802 1.97681 35.9202 1.97681 34.8V31.3682C1.97681 30.097 1.97681 29.4612 2.0729 28.9312C2.51933 26.4688 4.44921 24.5418 6.91509 24.096C7.06915 24.0682 7.23179 24.0484 7.41616 24.0344C7.86689 24 8.09225 23.9828 8.39329 24.0052C8.70618 24.0286 8.88117 24.0594 9.18315 24.1444C9.47366 24.2262 9.99696 24.463 11.0435 24.9364C12.2655 25.4892 13.5966 25.8436 14.9956 25.959M32.0202 31C32.0202 33.7614 29.7783 36 27.0129 36C24.2475 36 22.0057 33.7614 22.0057 31C22.0057 28.2386 24.2475 26 27.0129 26C29.7783 26 32.0202 28.2386 32.0202 31ZM24.0086 10C24.0086 14.4183 20.4216 18 15.997 18C11.5724 18 7.98548 14.4183 7.98548 10C7.98548 5.58172 11.5724 2 15.997 2C20.4216 2 24.0086 5.58172 24.0086 10Z" stroke={props.fill ? props.fill : "#DDF23D"} - stroke-width="3" - stroke-linecap="round" - stroke-linejoin="round" + strokeWidth="3" + strokeLinecap="round" + strokeLinejoin="round" /> ); From 7cece72cc183e078a501bda00d5180fdb2dad145 Mon Sep 17 00:00:00 2001 From: eduramme Date: Thu, 15 Feb 2024 20:24:39 -0300 Subject: [PATCH 068/305] fix grid --- components/01-atoms/EmptyNftsCards.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/EmptyNftsCards.tsx b/components/01-atoms/EmptyNftsCards.tsx index 261bd50b..1398267c 100644 --- a/components/01-atoms/EmptyNftsCards.tsx +++ b/components/01-atoms/EmptyNftsCards.tsx @@ -23,7 +23,7 @@ export const EmptyNftsCards = ( const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( <> -
+
)); From 4c964c170654128d9153c9bf2b5a5da7941fab29 Mon Sep 17 00:00:00 2001 From: eduramme Date: Thu, 15 Feb 2024 20:27:33 -0300 Subject: [PATCH 069/305] fix active tba --- components/01-atoms/SwappingIcons.tsx | 2 +- pages/index.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/01-atoms/SwappingIcons.tsx b/components/01-atoms/SwappingIcons.tsx index bd6047cf..e0bb177c 100644 --- a/components/01-atoms/SwappingIcons.tsx +++ b/components/01-atoms/SwappingIcons.tsx @@ -48,7 +48,7 @@ export const SwappingIcons = () => { { id: SwappingIconsID.OFFERS, name: "Offers", - href: "/offers/", + href: "/offers", icon: OffersIcon, }, { diff --git a/pages/index.tsx b/pages/index.tsx index e870d87b..f385c389 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,6 +1,5 @@ import { TheHeader } from "@/components/02-molecules"; import { Layout, SwapSection } from "@/components/04-templates"; -import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import cc from "classcat"; export default function IndexPage() { From b545fd614d020c335aa33856ec1564107c775c0e Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 16 Feb 2024 12:01:08 -0300 Subject: [PATCH 070/305] feat: add error finding swap offers component --- components/01-atoms/icons/ErrorIcon.tsx | 50 +++++++++++++++++++ components/01-atoms/icons/index.tsx | 1 + components/01-atoms/index.ts | 1 + .../02-molecules/ErrorFindingSwapOffers.tsx | 40 +++++++++++++++ components/02-molecules/index.tsx | 1 + components/04-templates/OfferSection.tsx | 11 ++-- styles/global.css | 3 ++ 7 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 components/01-atoms/icons/ErrorIcon.tsx create mode 100644 components/02-molecules/ErrorFindingSwapOffers.tsx diff --git a/components/01-atoms/icons/ErrorIcon.tsx b/components/01-atoms/icons/ErrorIcon.tsx new file mode 100644 index 00000000..cd41ccf3 --- /dev/null +++ b/components/01-atoms/icons/ErrorIcon.tsx @@ -0,0 +1,50 @@ +import { SVGProps } from "react"; +import cc from "classcat"; +import { useTheme } from "next-themes"; + +export const ErrorIcon = (props: SVGProps) => { + const { theme } = useTheme(); + return ( +
+ + + + + + + + + + + +
+ ); +}; diff --git a/components/01-atoms/icons/index.tsx b/components/01-atoms/icons/index.tsx index acb487cf..6cd76f8c 100644 --- a/components/01-atoms/icons/index.tsx +++ b/components/01-atoms/icons/index.tsx @@ -1,6 +1,7 @@ export * from "./ChatIcon"; export * from "./CheckIcon"; export * from "./DangerIcon"; +export * from "./ErrorIcon"; export * from "./EthereumIcon"; export * from "./LeftIcon"; export * from "./MagnifyingGlassIcon"; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 05ef7e16..04a11bfb 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -8,6 +8,7 @@ export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; export * from "./SelectDestinyChain"; export * from "./StatusOffers"; +export * from "./SwapAddManuallyModalLayout"; export * from "./SwapContext"; export * from "./SwapExpireTime"; export * from "./SwapModalButton"; diff --git a/components/02-molecules/ErrorFindingSwapOffers.tsx b/components/02-molecules/ErrorFindingSwapOffers.tsx new file mode 100644 index 00000000..7334201f --- /dev/null +++ b/components/02-molecules/ErrorFindingSwapOffers.tsx @@ -0,0 +1,40 @@ +import { SwapAddManuallyModalLayout } from "@/components/01-atoms"; +import { ErrorIcon } from "@/components/01-atoms/icons"; +import cc from "classcat"; +import { useTheme } from "next-themes"; +import { useState } from "react"; + +export const ErrorFindingSwapOffers = () => { + const { theme } = useTheme(); + const [toggleManually, setToggleManually] = useState(false); + return ( +
+
+ +
+
+

+ Sorry, we couldn't load your swaps +

+

+ Please try again later or add your swaps manually +

+
+
+ + { + setToggleManually(false); + }} + variant="swap" + /> +
+
+ ); +}; diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index 37ad81b6..cd264179 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -1,5 +1,6 @@ export * from "./CardHome"; export * from "./ConfirmSwapModal"; +export * from "./ErrorFindingSwapOffers"; export * from "./FilterOffers"; export * from "./NftCard"; export * from "./NftsList"; diff --git a/components/04-templates/OfferSection.tsx b/components/04-templates/OfferSection.tsx index dcc4ae3c..7c6eccb0 100644 --- a/components/04-templates/OfferSection.tsx +++ b/components/04-templates/OfferSection.tsx @@ -1,11 +1,16 @@ -import { FilterOffers } from "@/components/02-molecules"; +import { + ErrorFindingSwapOffers, + FilterOffers, +} from "@/components/02-molecules"; export const OfferSection = () => { return ( -
+
-
+
+
+
); diff --git a/styles/global.css b/styles/global.css index c08b39e7..56af0da6 100644 --- a/styles/global.css +++ b/styles/global.css @@ -71,6 +71,9 @@ input[type="search"]::-webkit-search-results-decoration { .p-medium-bold-2-dark { @apply font-onest font-medium text-[16px] leading-[20px] text-[#F6F6F6]; } + .p-medium-bold-2-dark-variant-black { + @apply font-onest font-medium text-[16px] leading-[20px] text-black; + } .p-medium-bold-variant-black { @apply font-onest font-medium text-[14px] leading-[16px] text-[#181A19]; From 936326a4f44d362755253b93d7cd00a34387897b Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 16 Feb 2024 12:29:08 -0300 Subject: [PATCH 071/305] update: requested-changes --- components/01-atoms/icons/ErrorIcon.tsx | 8 +++++--- components/02-molecules/ErrorFindingSwapOffers.tsx | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/01-atoms/icons/ErrorIcon.tsx b/components/01-atoms/icons/ErrorIcon.tsx index cd41ccf3..ec9dd9a2 100644 --- a/components/01-atoms/icons/ErrorIcon.tsx +++ b/components/01-atoms/icons/ErrorIcon.tsx @@ -8,7 +8,9 @@ export const ErrorIcon = (props: SVGProps) => {
) => { diff --git a/components/02-molecules/ErrorFindingSwapOffers.tsx b/components/02-molecules/ErrorFindingSwapOffers.tsx index 7334201f..aeb4ec57 100644 --- a/components/02-molecules/ErrorFindingSwapOffers.tsx +++ b/components/02-molecules/ErrorFindingSwapOffers.tsx @@ -10,7 +10,7 @@ export const ErrorFindingSwapOffers = () => { return (
- +

From 924a564c6dd99a72f84756dbd2c8d26f53b1c492 Mon Sep 17 00:00:00 2001 From: Deepu Date: Fri, 16 Feb 2024 23:17:35 +0530 Subject: [PATCH 072/305] closes #125 --- components/01-atoms/SearchBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index f7606530..10940022 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -81,7 +81,7 @@ export const SearchBar = () => { }, [loadingENSaddress]); return ( -

+

Who are you swapping with today? From 68ed85bded114762bddbbac6bc154285e52172c9 Mon Sep 17 00:00:00 2001 From: Deepu Date: Fri, 16 Feb 2024 23:36:09 +0530 Subject: [PATCH 073/305] Closes #125 --- components/01-atoms/SearchBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 10940022..50e6f6a5 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -81,7 +81,7 @@ export const SearchBar = () => { }, [loadingENSaddress]); return ( -
+

Who are you swapping with today? From 3a3a87e8cc201e5d5c32e8970ee4d5d4bfa70551 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 15:30:57 -0300 Subject: [PATCH 074/305] Fixed copyright typo --- components/02-molecules/TheHeader.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index c4857e2e..f7f2d4ba 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -34,7 +34,7 @@ export const TheHeader = () => { if (!mounted) return null; const currentTheme = theme === "system" ? systemTheme : theme; - const isDark = currentTheme === "dark" + const isDark = currentTheme === "dark"; return (
@@ -56,13 +56,19 @@ export const TheHeader = () => {
{isDark ? ( - - + ) : ( - - From 9b5981fa58c0821c545d627b4c10950a625f8134 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 15:38:45 -0300 Subject: [PATCH 075/305] Fixed ENSAvatar component loading state --- components/01-atoms/ENSAvatar.tsx | 20 +++++++++++--------- lib/client/hooks/useENSData.tsx | 11 ++++++++--- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/components/01-atoms/ENSAvatar.tsx b/components/01-atoms/ENSAvatar.tsx index b361dcbf..68f17f7d 100644 --- a/components/01-atoms/ENSAvatar.tsx +++ b/components/01-atoms/ENSAvatar.tsx @@ -1,9 +1,11 @@ -import { EthereumAddress } from "@/lib/shared/types"; -import BoringAvatar from "boring-avatars"; import { ENSAvatarQueryStatus, useEnsData, } from "@/lib/client/hooks/useENSData"; +import { EthereumAddress } from "@/lib/shared/types"; +import BoringAvatar from "boring-avatars"; +import cc from "classcat"; +import { LoadingIndicator } from "."; enum ENSAvatarSize { SMALL = "small", @@ -31,13 +33,13 @@ export const ENSAvatar = ({ return (
{avatarQueryStatus === ENSAvatarQueryStatus.LOADING ? ( -
- +
+
) : avatarQueryStatus === ENSAvatarQueryStatus.ERROR ? (
diff --git a/lib/client/hooks/useENSData.tsx b/lib/client/hooks/useENSData.tsx index bbd16880..ec1fe53d 100644 --- a/lib/client/hooks/useENSData.tsx +++ b/lib/client/hooks/useENSData.tsx @@ -1,7 +1,7 @@ +import { EthereumAddress } from "@/lib/shared/types"; import { createPublicClient, http } from "viem"; import { useEffect, useState } from "react"; import { mainnet } from "viem/chains"; -import { EthereumAddress } from "@/lib/shared/types"; export enum ENSAvatarQueryStatus { LOADING, @@ -17,6 +17,8 @@ export const useEnsData = ({ ensAddress }: Props) => { const [primaryName, setPrimaryName] = useState( undefined, ); + const [avatarQueryStatus, setAvatarQueryStatus] = + useState(ENSAvatarQueryStatus.LOADING); useEffect(() => { if (ensAddress) { @@ -25,15 +27,18 @@ export const useEnsData = ({ ensAddress }: Props) => { transport: http(), }); + setAvatarQueryStatus(ENSAvatarQueryStatus.LOADING); + mainnetClient .getEnsName({ address: ensAddress.address as `0x${string}`, }) .then((name) => { - console.log(name); + setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); setPrimaryName(name); }) .catch(() => { + setAvatarQueryStatus(ENSAvatarQueryStatus.ERROR); setPrimaryName(null); }); } else { @@ -43,7 +48,7 @@ export const useEnsData = ({ ensAddress }: Props) => { return { primaryName, - avatarQueryStatus: ENSAvatarQueryStatus.LOADING, + avatarQueryStatus: avatarQueryStatus, avatarSrc: primaryName ? `https://metadata.ens.domains/mainnet/avatar/${primaryName}` : null, From a218835b6a6a9410c0583faabdbfad5ca30c61ab Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 15:40:53 -0300 Subject: [PATCH 076/305] Fixed lint issues --- components/01-atoms/ENSAvatar.tsx | 2 +- lib/client/hooks/subgraphQueries.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/01-atoms/ENSAvatar.tsx b/components/01-atoms/ENSAvatar.tsx index 68f17f7d..742f4d91 100644 --- a/components/01-atoms/ENSAvatar.tsx +++ b/components/01-atoms/ENSAvatar.tsx @@ -1,3 +1,4 @@ +import { LoadingIndicator } from "."; import { ENSAvatarQueryStatus, useEnsData, @@ -5,7 +6,6 @@ import { import { EthereumAddress } from "@/lib/shared/types"; import BoringAvatar from "boring-avatars"; import cc from "classcat"; -import { LoadingIndicator } from "."; enum ENSAvatarSize { SMALL = "small", diff --git a/lib/client/hooks/subgraphQueries.ts b/lib/client/hooks/subgraphQueries.ts index 6c3e65db..112a34a9 100644 --- a/lib/client/hooks/subgraphQueries.ts +++ b/lib/client/hooks/subgraphQueries.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ require("dotenv").config(); import axios from "axios"; From 5b8bb0a1c4e6d8995b54669430e55a8ff2751ad3 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 16:33:03 -0300 Subject: [PATCH 077/305] Installed ethers --- package-lock.json | 188 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 7 +- 2 files changed, 192 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c667d93a..dbda7fe1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "boring-avatars": "1.7.0", "classcat": "^5.0.4", "eslint-plugin-unused-imports": "2.0.0", + "ethers": "^6.11.1", "next": "14.0.3", "next-auth": "^4.20.1", "next-themes": "^0.2.1", @@ -444,6 +445,126 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz", + "integrity": "sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz", + "integrity": "sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz", + "integrity": "sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz", + "integrity": "sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz", + "integrity": "sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz", + "integrity": "sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz", + "integrity": "sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz", + "integrity": "sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@noble/curves": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", @@ -4019,6 +4140,73 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "node_modules/ethers/node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", diff --git a/package.json b/package.json index 320e862e..08bdc0b3 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint --config .eslintrc" }, "dependencies": { "@headlessui-float/react": "^0.13.0", @@ -18,6 +18,7 @@ "boring-avatars": "1.7.0", "classcat": "^5.0.4", "eslint-plugin-unused-imports": "2.0.0", + "ethers": "^6.11.1", "next": "14.0.3", "next-auth": "^4.20.1", "next-themes": "^0.2.1", @@ -35,11 +36,11 @@ "@types/node-fetch": "^2.6.9", "@types/react": "^18", "@types/react-dom": "^18", - "eslint": "8.7.0", - "eslint-config-next": "13.4.19", "@typescript-eslint/eslint-plugin": "5.54.1", "autoprefixer": "^10.0.1", "dotenv": "^16.4.1", + "eslint": "8.7.0", + "eslint-config-next": "13.4.19", "postcss": "^8", "tailwindcss": "^3.3.0", "typescript": "^5" From d8106676769501d64a187bade88919f6c86d964e Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 18:45:07 -0300 Subject: [PATCH 078/305] Updated useENSData avatar query status setter --- lib/client/hooks/useENSData.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/client/hooks/useENSData.tsx b/lib/client/hooks/useENSData.tsx index ec1fe53d..ca50a076 100644 --- a/lib/client/hooks/useENSData.tsx +++ b/lib/client/hooks/useENSData.tsx @@ -34,8 +34,13 @@ export const useEnsData = ({ ensAddress }: Props) => { address: ensAddress.address as `0x${string}`, }) .then((name) => { - setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); - setPrimaryName(name); + if (name) { + setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); + setPrimaryName(name); + } else { + setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); + setPrimaryName(null); + } }) .catch(() => { setAvatarQueryStatus(ENSAvatarQueryStatus.ERROR); From b3e1f3b4d4eb2b6f9e0acf46ab2fe326d0115ef9 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 16 Feb 2024 19:00:39 -0300 Subject: [PATCH 079/305] Updated useENSData avatar query status setter --- lib/client/hooks/useENSData.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/hooks/useENSData.tsx b/lib/client/hooks/useENSData.tsx index ca50a076..88bbb548 100644 --- a/lib/client/hooks/useENSData.tsx +++ b/lib/client/hooks/useENSData.tsx @@ -38,7 +38,7 @@ export const useEnsData = ({ ensAddress }: Props) => { setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); setPrimaryName(name); } else { - setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); + setAvatarQueryStatus(ENSAvatarQueryStatus.ERROR); setPrimaryName(null); } }) From 9453a59f4cd30d2503ad0ad7b6d7cbe9123bf349 Mon Sep 17 00:00:00 2001 From: Blockchain User <90667119+0xneves@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:14:34 -0300 Subject: [PATCH 080/305] feat: adding public project id for wallet connect client --- .env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 9a498d10..965ed868 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= +NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=50db9e195634356bb8ab0375a9f07607 NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= @@ -14,4 +14,4 @@ NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= ENDPOINT_URL=https://api.studio.thegraph.com/query/57887/swaplace-subgraph-sepolia/version/latest -AUTHORIZATION_KEY=3b2048f02febad918a35bbafe78b2115 \ No newline at end of file +AUTHORIZATION_KEY=3b2048f02febad918a35bbafe78b2115 From ea4436c62ab5dce91731c06a25a56d6339c4badd Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 08:16:38 -0300 Subject: [PATCH 081/305] create sidebar component --- components/01-atoms/WalletSidebarTemplate.tsx | 22 +++ components/01-atoms/index.ts | 1 + components/02-molecules/TheHeader.tsx | 170 ++++++++++-------- tailwind.config.ts | 4 +- 4 files changed, 119 insertions(+), 78 deletions(-) create mode 100644 components/01-atoms/WalletSidebarTemplate.tsx diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx new file mode 100644 index 00000000..2d399416 --- /dev/null +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import cc from "classcat"; + +interface WalletSidebarTemplateProps { + isOpen: boolean; + isMobile: boolean; +} + +export const WalletSidebarTemplate = ({ + isOpen, + isMobile, +}: WalletSidebarTemplateProps) => { + return ( +
+ ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index fcbc8dd0..c8a6d893 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -24,3 +24,4 @@ export * from "./icons/SunIcon"; export * from "./icons/PaperPlane"; export * from "./icons/MagnifyingGlassIcon"; export * from "./icons/SelectUserIcon"; +export * from "./WalletSidebarTemplate"; diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 421d7889..226dbc48 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -6,6 +6,7 @@ import { MoonIcon, SunIcon, Tooltip, + WalletSidebarTemplate, } from "@/components/01-atoms"; import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; @@ -20,6 +21,12 @@ export const TheHeader = () => { const [showFullNav, setShowFullNav] = useState( !isDesktop && !!authenticatedUserAddress?.address, ); + const [isSidebarOpen, setIsSidebarOpen] = useState(false); + + const toggleSidebar = () => { + console.log("toggle"); + setIsSidebarOpen(!isSidebarOpen); + }; const { isWideScreen } = useScreenSize(); @@ -39,85 +46,94 @@ export const TheHeader = () => { const isDark = currentTheme === "dark"; return ( -
-
- - - -
- + <> +
+
+ + + +
+ +
-
-
- -
-
-
- {isDark ? ( - - - - ) : ( - - - - )} +
+
-
- {isWideScreen ? ( - <> - {!!authenticatedUserAddress ? ( - - - - ) : ( - -
- -
-
- )} - - ) : ( - <> - {!!authenticatedUserAddress ? ( - - - - ) : ( - -
- -
-
- )} - - )} +
+
+ {isDark ? ( + + + + ) : ( + + + + )} +
+
+ {isWideScreen ? ( + <> + {!!authenticatedUserAddress ? ( + + + + ) : ( + +
+ +
+
+ )} + + ) : ( + <> + {!!authenticatedUserAddress ? ( + + + + ) : ( + +
+ +
+
+ )} + + )} +
-
-
+
+ + ); }; diff --git a/tailwind.config.ts b/tailwind.config.ts index 1b153880..6c687625 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -12,9 +12,11 @@ const config: Config = { fontFamily: { onest: ["var(--font-onest)"], }, + boxShadow: { + custom: "0px 0px 12px 1px rgba(0, 0, 0, 0.40)", + }, }, }, - plugins: [], }; export default config; From 9509d60e79673b7c49b93a2ca854106bd5245d79 Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 08:49:46 -0300 Subject: [PATCH 082/305] apply blur on background --- components/01-atoms/WalletSidebarTemplate.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index 2d399416..7cc5c07c 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -11,12 +11,21 @@ export const WalletSidebarTemplate = ({ isMobile, }: WalletSidebarTemplateProps) => { return ( + <> + {/*
*/} +
+ {/*
*/} +
+ + ); }; From a9d18775269f882930b2d81bab32025bb3335e14 Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 08:58:38 -0300 Subject: [PATCH 083/305] fix blur --- components/01-atoms/WalletSidebarTemplate.tsx | 36 +++++++++++-------- tailwind.config.ts | 3 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index 7cc5c07c..b5f450b3 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -1,5 +1,6 @@ import React from "react"; import cc from "classcat"; +import { useTheme } from "next-themes"; interface WalletSidebarTemplateProps { isOpen: boolean; @@ -10,22 +11,29 @@ export const WalletSidebarTemplate = ({ isOpen, isMobile, }: WalletSidebarTemplateProps) => { + const { systemTheme, theme } = useTheme(); + const currentTheme = theme === "system" ? systemTheme : theme; + const isDark = currentTheme === "dark"; + return ( <> - {/*
*/} -
- {/*
*/} - -
+
+ +
- ); }; diff --git a/tailwind.config.ts b/tailwind.config.ts index 6c687625..cd6c8c88 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -13,7 +13,8 @@ const config: Config = { onest: ["var(--font-onest)"], }, boxShadow: { - custom: "0px 0px 12px 1px rgba(0, 0, 0, 0.40)", + sidebarLight: "0px 0px 6px 1px rgba(0, 0, 0, 0.30)", + sidebarDark: "0px 0px 12px 1px rgba(0, 0, 0, 0.40)" }, }, }, From a9bf2afd249ed9568d1d54b7727a0446f08683bf Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 09:01:46 -0300 Subject: [PATCH 084/305] remove console log --- components/02-molecules/TheHeader.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 226dbc48..93822e19 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -24,7 +24,6 @@ export const TheHeader = () => { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const toggleSidebar = () => { - console.log("toggle"); setIsSidebarOpen(!isSidebarOpen); }; From c3e4074cf51f345b884c6702001119214d14b1d6 Mon Sep 17 00:00:00 2001 From: Deepu Date: Sat, 17 Feb 2024 18:23:54 +0530 Subject: [PATCH 085/305] closes #128 --- .env.example | 2 +- lib/client/hooks/subgraphQueries.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index a7021669..ff90f7a4 100644 --- a/.env.example +++ b/.env.example @@ -14,4 +14,4 @@ NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= ENDPOINT_URL=https://api.studio.thegraph.com/query/57887/swaplace-subgraph-sepolia/version/latest -AUTHORIZATION_KEY=3b2048f02febad918a35bbafe78b2115 +SUBGRAPH_AUTH_KEY=3b2048f02febad918a35bbafe78b2115 diff --git a/lib/client/hooks/subgraphQueries.ts b/lib/client/hooks/subgraphQueries.ts index 112a34a9..19c618af 100644 --- a/lib/client/hooks/subgraphQueries.ts +++ b/lib/client/hooks/subgraphQueries.ts @@ -6,7 +6,7 @@ export const getGraphQuery = async () => { const endpoint = process.env.ENDPOINT_URL; const headers = { "content-type": "application/json", - Authorization: process.env.AUTHORIZATION_KEY, + Authorization: process.env.SUBGRAPH_AUTH_KEY, }; //Example of query From 9e696da779b8f1f396f833d0efb6fafc47318f1e Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 13:33:05 -0300 Subject: [PATCH 086/305] Create TheSidebarHeader for the WalletSidebarTemplate --- components/01-atoms/WalletSidebarTemplate.tsx | 5 ++++- components/02-molecules/TheSidebarHeader.tsx | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 components/02-molecules/TheSidebarHeader.tsx diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index b5f450b3..52f1e277 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -1,3 +1,4 @@ +import { TheSidebarHeader } from "../02-molecules/TheSidebarHeader"; import React from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; @@ -33,7 +34,9 @@ export const WalletSidebarTemplate = ({ isOpen ? "translate-x-0" : "translate-x-full", isMobile ? "w-full" : "w-[400px]", ])} - >
+ > + +
); }; diff --git a/components/02-molecules/TheSidebarHeader.tsx b/components/02-molecules/TheSidebarHeader.tsx new file mode 100644 index 00000000..ba8b2042 --- /dev/null +++ b/components/02-molecules/TheSidebarHeader.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +export const TheSidebarHeader = () => { + return ( +
+ +
+ ); +}; From e4381ccb242d06233384b8324ee93e5e6817030a Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 14:13:22 -0300 Subject: [PATCH 087/305] create design --- .../01-atoms/SwapAddManuallyModalLayout.tsx | 2 +- components/01-atoms/SwapModalLayout.tsx | 2 +- components/01-atoms/icons/CloseIcon.tsx | 4 +- components/01-atoms/icons/PowerIcon.tsx | 26 +++++++++++++ components/02-molecules/TheSidebarHeader.tsx | 37 ++++++++++++++++++- 5 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 components/01-atoms/icons/PowerIcon.tsx diff --git a/components/01-atoms/SwapAddManuallyModalLayout.tsx b/components/01-atoms/SwapAddManuallyModalLayout.tsx index 16507d5a..30f9606d 100644 --- a/components/01-atoms/SwapAddManuallyModalLayout.tsx +++ b/components/01-atoms/SwapAddManuallyModalLayout.tsx @@ -160,7 +160,7 @@ export const SwapAddManuallyModalLayout = ({ {AddManuallyVariantConfig[variant].header}
- +

{AddManuallyVariantConfig[variant].body}
diff --git a/components/01-atoms/SwapModalLayout.tsx b/components/01-atoms/SwapModalLayout.tsx index 9109ec35..9d31440c 100644 --- a/components/01-atoms/SwapModalLayout.tsx +++ b/components/01-atoms/SwapModalLayout.tsx @@ -78,7 +78,7 @@ export const SwapModalLayout = ({

diff --git a/components/01-atoms/icons/CloseIcon.tsx b/components/01-atoms/icons/CloseIcon.tsx index ae0f93a2..c7e9b65d 100644 --- a/components/01-atoms/icons/CloseIcon.tsx +++ b/components/01-atoms/icons/CloseIcon.tsx @@ -8,14 +8,14 @@ export const CloseIcon = (props: SVGProps) => { width="14" height="14" viewBox="0 0 14 14" - fill={props.fill ? props.fill : "black"} + fill={"currentColor"} xmlns="http://www.w3.org/2000/svg" > diff --git a/components/01-atoms/icons/PowerIcon.tsx b/components/01-atoms/icons/PowerIcon.tsx new file mode 100644 index 00000000..f76359b4 --- /dev/null +++ b/components/01-atoms/icons/PowerIcon.tsx @@ -0,0 +1,26 @@ +import { SVGProps } from "react"; + +export const PowerIcon = (props: SVGProps) => { + return ( + + + + + + + + + + + ); +}; diff --git a/components/02-molecules/TheSidebarHeader.tsx b/components/02-molecules/TheSidebarHeader.tsx index ba8b2042..235a2b9f 100644 --- a/components/02-molecules/TheSidebarHeader.tsx +++ b/components/02-molecules/TheSidebarHeader.tsx @@ -1,9 +1,42 @@ +import { CloseIcon } from "../01-atoms/icons/CloseIcon"; +import { PowerIcon } from "../01-atoms/icons/PowerIcon"; import React from "react"; +import cc from "classcat"; +import { useTheme } from "next-themes"; export const TheSidebarHeader = () => { - return ( -
+ const { systemTheme, theme } = useTheme(); + const currentTheme = theme === "system" ? systemTheme : theme; + const isDark = currentTheme === "dark"; + return ( +
+ +
+

+ Your wallet +

+
+ +

Disconnect

+
+
); }; From abc5277bd289284f97b9b61778c5a594181b7b3c Mon Sep 17 00:00:00 2001 From: eduramme Date: Sat, 17 Feb 2024 15:23:58 -0300 Subject: [PATCH 088/305] disconnect wallet when disconnect button clicked --- components/01-atoms/DisconnectWallet.tsx | 31 ++++++++++++++++++++ components/02-molecules/TheHeader.tsx | 6 ++-- components/02-molecules/TheSidebarHeader.tsx | 11 +++---- components/04-templates/Layout.tsx | 3 +- lib/client/contexts/SidebarContext.tsx.tsx | 30 +++++++++++++++++++ pages/index.tsx | 16 +++++----- 6 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 components/01-atoms/DisconnectWallet.tsx create mode 100644 lib/client/contexts/SidebarContext.tsx.tsx diff --git a/components/01-atoms/DisconnectWallet.tsx b/components/01-atoms/DisconnectWallet.tsx new file mode 100644 index 00000000..f496df67 --- /dev/null +++ b/components/01-atoms/DisconnectWallet.tsx @@ -0,0 +1,31 @@ +import { PowerIcon } from "./icons/PowerIcon"; +import { useSidebar } from "@/lib/client/contexts/SidebarContext.tsx"; +import { useDisconnect } from "wagmi"; +import cc from "classcat" +import { useTheme } from "next-themes"; + +export const DisconnectWallet = () => { + const { disconnect } = useDisconnect(); + const { systemTheme, theme } = useTheme(); + const currentTheme = theme === "system" ? systemTheme : theme; + const isDark = currentTheme === "dark"; + const { toggleSidebar } = useSidebar(); + + const handleClick = () => { + toggleSidebar() + disconnect() + } + + return ( + + ); +}; diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 93822e19..ce7e1712 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -10,6 +10,7 @@ import { } from "@/components/01-atoms"; import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import { useSidebar } from "@/lib/client/contexts/SidebarContext.tsx"; import React, { useEffect, useState } from "react"; import { useTheme } from "next-themes"; import Link from "next/link"; @@ -21,11 +22,8 @@ export const TheHeader = () => { const [showFullNav, setShowFullNav] = useState( !isDesktop && !!authenticatedUserAddress?.address, ); - const [isSidebarOpen, setIsSidebarOpen] = useState(false); - const toggleSidebar = () => { - setIsSidebarOpen(!isSidebarOpen); - }; + const { toggleSidebar, isSidebarOpen } = useSidebar(); const { isWideScreen } = useScreenSize(); diff --git a/components/02-molecules/TheSidebarHeader.tsx b/components/02-molecules/TheSidebarHeader.tsx index 235a2b9f..30bfd454 100644 --- a/components/02-molecules/TheSidebarHeader.tsx +++ b/components/02-molecules/TheSidebarHeader.tsx @@ -1,5 +1,6 @@ import { CloseIcon } from "../01-atoms/icons/CloseIcon"; -import { PowerIcon } from "../01-atoms/icons/PowerIcon"; +import { DisconnectWallet } from "../01-atoms/DisconnectWallet"; +import { useSidebar } from "@/lib/client/contexts/SidebarContext.tsx"; import React from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; @@ -8,10 +9,13 @@ export const TheSidebarHeader = () => { const { systemTheme, theme } = useTheme(); const currentTheme = theme === "system" ? systemTheme : theme; const isDark = currentTheme === "dark"; + const { toggleSidebar } = useSidebar(); + return (

-
- -

Disconnect

-
+
); diff --git a/components/04-templates/Layout.tsx b/components/04-templates/Layout.tsx index 98edf288..db81c87d 100644 --- a/components/04-templates/Layout.tsx +++ b/components/04-templates/Layout.tsx @@ -1,8 +1,9 @@ /* eslint-disable react-hooks/exhaustive-deps */ +import { SidebarProvider } from "@/lib/client/contexts/SidebarContext.tsx"; import { useAuthedAccess } from "@/lib/client/hooks/useAuthedAccess"; export const Layout = ({ children }: { children: React.ReactNode }) => { useAuthedAccess(); - return <>{children}; + return {children}; }; diff --git a/lib/client/contexts/SidebarContext.tsx.tsx b/lib/client/contexts/SidebarContext.tsx.tsx new file mode 100644 index 00000000..afc706c5 --- /dev/null +++ b/lib/client/contexts/SidebarContext.tsx.tsx @@ -0,0 +1,30 @@ +import React, { createContext, useContext, useState, ReactNode, useCallback } from 'react'; + +interface SidebarContextType { + isSidebarOpen: boolean; + toggleSidebar: () => void; +} + +const SidebarContext = createContext(undefined); + +export const SidebarProvider = ({ children }: { children: ReactNode }) => { + const [isSidebarOpen, setIsSidebarOpen] = useState(false); + + const toggleSidebar = useCallback(() => { + setIsSidebarOpen((prevState) => !prevState); + }, []); + + return ( + + {children} + + ); +}; + +export const useSidebar = () => { + const context = useContext(SidebarContext); + if (context === undefined) { + throw new Error('useSidebar must be used within a SidebarProvider'); + } + return context; +}; diff --git a/pages/index.tsx b/pages/index.tsx index f385c389..ed4a9a8e 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -5,14 +5,14 @@ import cc from "classcat"; export default function IndexPage() { return ( -
- - -
+
+ + +
); } From 0d5aa8e346757065c574002ecdc8561c3d8bcdce Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 18:39:53 -0300 Subject: [PATCH 089/305] fix: add pr 103 at a218835 --- .env.example | 8 +++--- README.md | 31 ++++++++++++++++++++++ components/01-atoms/ConnectWallet.tsx | 2 +- components/01-atoms/SearchBar.tsx | 3 +-- components/01-atoms/SelectDestinyChain.tsx | 3 +-- components/01-atoms/SwapModalButton.tsx | 3 +-- components/01-atoms/SwappingIcons.tsx | 11 +++----- components/01-atoms/icons/index.tsx | 20 -------------- components/01-atoms/index.ts | 20 ++++++++++++++ components/02-molecules/CardHome.tsx | 3 +-- components/02-molecules/NftCard.tsx | 1 + components/02-molecules/NftsList.tsx | 8 +++++- components/02-molecules/OfferSummary.tsx | 3 +-- components/02-molecules/SwapStation.tsx | 3 +-- components/02-molecules/TheHeader.tsx | 6 +++-- components/03-organisms/NftsShelf.tsx | 3 +-- components/04-templates/Layout.tsx | 1 + lib/client/blockchain-data.ts | 4 +-- lib/client/constants.ts | 6 +---- lib/client/hooks/useENSData.tsx | 9 +++++-- styles/global.css | 16 +++++++++++ 21 files changed, 106 insertions(+), 58 deletions(-) delete mode 100644 components/01-atoms/icons/index.tsx diff --git a/.env.example b/.env.example index 9a498d10..496cc963 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,16 @@ -NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= +NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=50db9e195634356bb8ab0375a9f07607 NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY= NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= -#Subgraph endpoint production query +# Subgraph endpoint production query -#ENDPOINT_URL=https://gateway.testnet.thegraph.com/api/[api-key]/subgraphs/id/EynHJVht9r6xhaZEPCyLYLd4EqBq8msf4jTrw1Vwg8ZV +# ENDPOINT_URL=https://gateway.testnet.thegraph.com/api/[api-key]/subgraphs/id/EynHJVht9r6xhaZEPCyLYLd4EqBq8msf4jTrw1Vwg8ZV -#Subgraph endpoint production query +# Subgraph endpoint production query ENDPOINT_URL=https://api.studio.thegraph.com/query/57887/swaplace-subgraph-sepolia/version/latest diff --git a/README.md b/README.md index 45f1d403..ef85d40b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ## Swaplace +This repository contains the core frontend for the Swaplace Protocol; The lightest Swap protocol in the market. + +## Setup + First, install the dependences: ```bash @@ -17,3 +21,30 @@ pnpm dev # or bun dev ``` + +### Environment Variables + +The project comes with a `.env.example` file. You should rename it to `.env` and fill the variables with your values. Most RPC providers offer free testnet nodes. You can use [Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/) to get a free node. + +``` +NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= +NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= +NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= +NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY= +NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= +``` + +WARNING: The private keys used in the `.env` file are from hardhat accounts. They are not meant to be used in production. + +WARNING: The `NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=` used in the `.env` file is public. They are not meant to be used in production. + +If you want use your own please create your Project ID in the [WalletConnect](https://cloud.walletconnect.com/) + +``` +NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= + +``` + +## Contributing + +- To know more about how you can contribute [see our notion page](https://blockful.notion.site/Swaplace-Call-for-Contributors-6e4895d2a7264f679439ab2c124603fe). diff --git a/components/01-atoms/ConnectWallet.tsx b/components/01-atoms/ConnectWallet.tsx index 677e6485..77944f21 100644 --- a/components/01-atoms/ConnectWallet.tsx +++ b/components/01-atoms/ConnectWallet.tsx @@ -1,4 +1,4 @@ -import { WalletIcon } from "./icons"; +import { WalletIcon } from "@/components/01-atoms"; import { ConnectButton } from "@rainbow-me/rainbowkit"; import { useRouter } from "next/router"; diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 758cd61d..6c6e4aa1 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -1,8 +1,7 @@ /* eslint-disable import/no-named-as-default */ /* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable import/no-named-as-default-member */ -import { MagnifyingGlassIcon } from "@/components/01-atoms/icons"; -import { SwapContext } from "@/components/01-atoms"; +import { MagnifyingGlassIcon, SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useContext, useEffect, useState } from "react"; import { useTheme } from "next-themes"; diff --git a/components/01-atoms/SelectDestinyChain.tsx b/components/01-atoms/SelectDestinyChain.tsx index 11e48477..ebcfebcb 100644 --- a/components/01-atoms/SelectDestinyChain.tsx +++ b/components/01-atoms/SelectDestinyChain.tsx @@ -1,5 +1,4 @@ -import { SwapContext } from "@/components/01-atoms"; -import { EthereumIcon, PolygonIcon } from "@/components/01-atoms/icons"; +import { EthereumIcon, PolygonIcon, SwapContext } from "@/components/01-atoms"; import { ChainInfo, SupportedNetworks } from "@/lib/client/constants"; import { Fragment, useContext, useState } from "react"; import { Dialog, Transition } from "@headlessui/react"; diff --git a/components/01-atoms/SwapModalButton.tsx b/components/01-atoms/SwapModalButton.tsx index 2858cf59..44f47b29 100644 --- a/components/01-atoms/SwapModalButton.tsx +++ b/components/01-atoms/SwapModalButton.tsx @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import { SwapContext } from "."; import { LoadingIndicator } from "./LoadingIndicator"; -import { LeftIcon, RightIcon } from "@/components/01-atoms/icons"; +import { LeftIcon, RightIcon, SwapContext } from "@/components/01-atoms"; import React, { ButtonHTMLAttributes, useContext } from "react"; import { useTheme } from "next-themes"; import cc from "classcat"; diff --git a/components/01-atoms/SwappingIcons.tsx b/components/01-atoms/SwappingIcons.tsx index e0bb177c..cac7d3ce 100644 --- a/components/01-atoms/SwappingIcons.tsx +++ b/components/01-atoms/SwappingIcons.tsx @@ -3,8 +3,9 @@ import { OffersIcon, ChatIcon, NotificationsIcon, -} from "@/components/01-atoms/icons"; -import { Tooltip } from "@/components/01-atoms"; + Tooltip, +} from "@/components/01-atoms"; + import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; import { useTheme } from "next-themes"; import { NextRouter, useRouter } from "next/router"; @@ -88,7 +89,6 @@ export const SwappingIcons = () => { return (
{isWideScreen ? ( -
{ ? "text-[#AABE13]" : "text-[#c1c3c2] group-hover:text-[#4F4F4F]", isDisabled && "disabled cursor-not-allowed", - ])} />
) : ( -
{ "flex-1 md:p-4 cursor-pointer hover:dark:bg-[#343635] hover:bg-[#eff3cf]", ])} onClick={() => { - handleClick(swappingTab); }} > @@ -150,7 +147,7 @@ export const SwappingIcons = () => {
)} - +
); })} diff --git a/components/01-atoms/icons/index.tsx b/components/01-atoms/icons/index.tsx deleted file mode 100644 index acb487cf..00000000 --- a/components/01-atoms/icons/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export * from "./ChatIcon"; -export * from "./CheckIcon"; -export * from "./DangerIcon"; -export * from "./EthereumIcon"; -export * from "./LeftIcon"; -export * from "./MagnifyingGlassIcon"; -export * from "./NotificationsIcon"; -export * from "./OffersIcon"; -export * from "./PaperPlane"; -export * from "./PersonIcon"; -export * from "./PolygonIcon"; -export * from "./RightIcon"; -export * from "./SelectUserIcon"; -export * from "./SwapIcon"; -export * from "./SwaplaceIcon"; -export * from "./SwappingIcon"; -export * from "./XMarkIcon"; -export * from "./WalletIcon"; -export * from "./SunIcon"; -export * from "./MoonIcon"; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index cf9e2787..9dd82add 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -15,3 +15,23 @@ export * from "./SwappingIcons"; export * from "./Tab"; export * from "./Tooltip"; export * from "./ENSAvatar"; +export * from "./icons/ChatIcon"; +export * from "./icons/CheckIcon"; +export * from "./icons/DangerIcon"; +export * from "./icons/EthereumIcon"; +export * from "./icons/LeftIcon"; +export * from "./icons/MagnifyingGlassIcon"; +export * from "./icons/NotificationsIcon"; +export * from "./icons/OffersIcon"; +export * from "./icons/PaperPlane"; +export * from "./icons/PersonIcon"; +export * from "./icons/PolygonIcon"; +export * from "./icons/RightIcon"; +export * from "./icons/SelectUserIcon"; +export * from "./icons/SwapIcon"; +export * from "./icons/SwaplaceIcon"; +export * from "./icons/SwappingIcon"; +export * from "./icons/XMarkIcon"; +export * from "./icons/WalletIcon"; +export * from "./icons/SunIcon"; +export * from "./icons/MoonIcon"; diff --git a/components/02-molecules/CardHome.tsx b/components/02-molecules/CardHome.tsx index 4985fabd..5f9f60e3 100644 --- a/components/02-molecules/CardHome.tsx +++ b/components/02-molecules/CardHome.tsx @@ -1,5 +1,4 @@ -import { ConnectWallet } from "@/components/01-atoms"; -import { SwaplaceIcon } from "@/components/01-atoms/icons"; +import { ConnectWallet, SwaplaceIcon } from "@/components/01-atoms"; import React from "react"; export const CardHome = () => { diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index f33fa3ab..e04247ff 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { NFT } from "@/lib/client/constants"; import { SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index 1c2e6e99..58b56174 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -1,7 +1,13 @@ -import { INftsList, NFT } from "@/lib/client/constants"; +import { NFT } from "@/lib/client/constants"; import { NftCard } from "@/components/02-molecules"; import { EmptyNftsCards } from "@/components/01-atoms"; +/* eslint-disable react/jsx-key */ +interface INftsList { + nftsList: NFT[]; + ownerAddress: string | null; +} + /** * * This component receives the data of multiple nfts and create its cards diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 70596b56..bccf2d02 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -1,8 +1,7 @@ import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { PersonIcon } from "@/components/01-atoms/icons"; import { NftCard } from "@/components/02-molecules"; -import { EmptyNftsCards, SwapContext } from "@/components/01-atoms"; +import { EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; import { useEnsName } from "wagmi"; import { useContext } from "react"; diff --git a/components/02-molecules/SwapStation.tsx b/components/02-molecules/SwapStation.tsx index 6c6c7a64..4910fec0 100644 --- a/components/02-molecules/SwapStation.tsx +++ b/components/02-molecules/SwapStation.tsx @@ -1,5 +1,4 @@ -import { SwapContext, SwapExpireTime } from "@/components/01-atoms"; -import { PaperPlane } from "@/components/01-atoms/icons"; +import { PaperPlane, SwapContext, SwapExpireTime } from "@/components/01-atoms"; import { ConfirmSwapModal, OfferSummary } from "@/components/02-molecules"; import { useContext, useEffect, useState } from "react"; import cc from "classcat"; diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index f7f2d4ba..b58bbeb0 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -3,12 +3,14 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { ConnectWallet, ENSAvatar, + MoonIcon, + SunIcon, + SwaplaceIcon, SwappingIcons, Tooltip, } from "@/components/01-atoms"; -import { MoonIcon, SunIcon, SwaplaceIcon } from "@/components/01-atoms/icons/"; -import { useTheme } from "next-themes"; import React, { useEffect, useState } from "react"; +import { useTheme } from "next-themes"; import Link from "next/link"; import cc from "classcat"; diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 17aab793..fe71f0d7 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -3,8 +3,7 @@ import { NFT, ChainInfo, NFTsQueryStatus } from "@/lib/client/constants"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { getNftsFrom } from "@/lib/client/blockchain-data"; import { EthereumAddress } from "@/lib/shared/types"; -import { SwapContext } from "@/components/01-atoms"; -import { SelectUserIcon } from "@/components/01-atoms/icons"; +import { SelectUserIcon, SwapContext } from "@/components/01-atoms"; import { NftsList } from "@/components/02-molecules"; import { useContext, useEffect, useState } from "react"; import { useTheme } from "next-themes"; diff --git a/components/04-templates/Layout.tsx b/components/04-templates/Layout.tsx index 10436a5a..98edf288 100644 --- a/components/04-templates/Layout.tsx +++ b/components/04-templates/Layout.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { useAuthedAccess } from "@/lib/client/hooks/useAuthedAccess"; export const Layout = ({ children }: { children: React.ReactNode }) => { diff --git a/lib/client/blockchain-data.ts b/lib/client/blockchain-data.ts index 6fce855d..3a48525b 100644 --- a/lib/client/blockchain-data.ts +++ b/lib/client/blockchain-data.ts @@ -1,7 +1,7 @@ -import { NFT, NFTsQueryStatus, getRpcHttpUrlForNetwork } from "./constants"; import { getTimestamp } from "./utils"; -import { hexToNumber } from "viem"; +import { NFT, NFTsQueryStatus, getRpcHttpUrlForNetwork } from "./constants"; import { Dispatch, SetStateAction } from "react"; +import { hexToNumber } from "viem"; export interface ICreateSwap { walletClient: any; diff --git a/lib/client/constants.ts b/lib/client/constants.ts index 1f7e3e46..a90473b0 100644 --- a/lib/client/constants.ts +++ b/lib/client/constants.ts @@ -1,3 +1,4 @@ +/* eslint-disable prefer-const */ export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; export const WIDE_SCREEN_SIZE = 1279; @@ -11,11 +12,6 @@ export interface NFT { contractMetadata?: Record; } -export interface INftsList { - nftsList: NFT[]; - ownerAddress: string | null; -} - export enum NFTsQueryStatus { EMPTY_QUERY = "EMPTY_QUERY", LOADING = "LOADING", diff --git a/lib/client/hooks/useENSData.tsx b/lib/client/hooks/useENSData.tsx index ec1fe53d..88bbb548 100644 --- a/lib/client/hooks/useENSData.tsx +++ b/lib/client/hooks/useENSData.tsx @@ -34,8 +34,13 @@ export const useEnsData = ({ ensAddress }: Props) => { address: ensAddress.address as `0x${string}`, }) .then((name) => { - setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); - setPrimaryName(name); + if (name) { + setAvatarQueryStatus(ENSAvatarQueryStatus.SUCCESS); + setPrimaryName(name); + } else { + setAvatarQueryStatus(ENSAvatarQueryStatus.ERROR); + setPrimaryName(null); + } }) .catch(() => { setAvatarQueryStatus(ENSAvatarQueryStatus.ERROR); diff --git a/styles/global.css b/styles/global.css index 6c059cbc..34f520da 100644 --- a/styles/global.css +++ b/styles/global.css @@ -15,6 +15,13 @@ input[type="search"]::-webkit-search-results-decoration { @tailwind utilities; @layer utilities { + .shadow-add-manually-card { + box-shadow: 0px 0px 12px 1px #00000066; + } + .shadow-add-manually-button { + box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.3); + } + .title-h1 { } @@ -64,7 +71,13 @@ input[type="search"]::-webkit-search-results-decoration { .p-medium-bold-2-dark { @apply font-onest font-medium text-[16px] leading-[20px] text-[#F6F6F6]; } + .p-medium-bold-2-dark-variant-black { + @apply font-onest font-medium text-[16px] leading-[20px] text-black; + } + .p-medium-bold-variant-black { + @apply font-onest font-medium text-[14px] leading-[16px] text-[#181A19]; + } .p-medium-bold { @apply font-onest font-medium text-[14px] leading-[16px] text-[#707572]; } @@ -79,6 +92,9 @@ input[type="search"]::-webkit-search-results-decoration { @apply font-onest font-medium text-[14px] leading-[20px] text-[#F6F6F6]; } + .p-small-variant-black { + @apply font-onest font-normal text-[14px] leading-[20px] text-[#181A19]; + } .p-small { @apply font-onest font-normal text-[14px] leading-[20px] text-[#707572]; } From cad5bbe19c6c2e77c0962dc8b8fcc9bf6652d2f2 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 18:59:01 -0300 Subject: [PATCH 090/305] fix: add pr 103 at fc3e13f --- .eslintrc.json => .eslintrc | 0 .github/workflows/eslint.yml | 50 ++++++++++++++++++++++++++++ lib/client/hooks/useAuthedAccess.tsx | 1 + 3 files changed, 51 insertions(+) rename .eslintrc.json => .eslintrc (100%) create mode 100644 .github/workflows/eslint.yml diff --git a/.eslintrc.json b/.eslintrc similarity index 100% rename from .eslintrc.json rename to .eslintrc diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 00000000..5fd22417 --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,50 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# ESLint is a tool for identifying and reporting on patterns +# found in ECMAScript/JavaScript code. +# More details at https://github.com/eslint/eslint +# and https://eslint.org + +name: ESLint + +on: + push: + branches: ["main"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["main"] + schedule: + - cron: "16 6 * * 3" + +jobs: + eslint: + name: Run eslint scanning + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install ESLint + run: | + npm install eslint@8.10.0 --legacy-peer-deps + npm install @microsoft/eslint-formatter-sarif@2.1.7 --legacy-peer-deps + + - name: Run ESLint + run: npx eslint . + --config .eslintrc.json + --ext .js,.jsx,.ts,.tsx + --format @microsoft/eslint-formatter-sarif + --output-file eslint-results.sarif + continue-on-error: true + + - name: Upload analysis results to GitHub + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: eslint-results.sarif + wait-for-processing: true diff --git a/lib/client/hooks/useAuthedAccess.tsx b/lib/client/hooks/useAuthedAccess.tsx index 677e5fda..6138d402 100644 --- a/lib/client/hooks/useAuthedAccess.tsx +++ b/lib/client/hooks/useAuthedAccess.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { useAuthenticatedUser } from "./useAuthenticatedUser"; import { useRouter } from "next/router"; import { useEffect } from "react"; From 766aa6fbcda568ea008de37a01c778f16f09d3e8 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 19:09:29 -0300 Subject: [PATCH 091/305] fix: add pr 103 at 986fd05 --- .github/workflows/eslint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 5fd22417..b2bb4788 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -37,7 +37,7 @@ jobs: - name: Run ESLint run: npx eslint . - --config .eslintrc.json + --config .eslintrc --ext .js,.jsx,.ts,.tsx --format @microsoft/eslint-formatter-sarif --output-file eslint-results.sarif From d447b83d9f74e23be6ad8dea324dce2aa0fabcd0 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 19:35:33 -0300 Subject: [PATCH 092/305] fix: add pr 103 package.json --- components/01-atoms/SwapOfferDetails.tsx | 2 +- package-lock.json | 257 ++++++----------------- package.json | 6 +- 3 files changed, 67 insertions(+), 198 deletions(-) diff --git a/components/01-atoms/SwapOfferDetails.tsx b/components/01-atoms/SwapOfferDetails.tsx index 65614683..76be3e79 100644 --- a/components/01-atoms/SwapOfferDetails.tsx +++ b/components/01-atoms/SwapOfferDetails.tsx @@ -1,4 +1,4 @@ -import { CheckIcon, XMarkIcon } from "./icons"; +import { CheckIcon, XMarkIcon } from "@/components/01-atoms"; import React from "react"; export const SwapOfferDetails = () => ( diff --git a/package-lock.json b/package-lock.json index 1fe38235..a0e31293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,8 +38,8 @@ "@typescript-eslint/parser": "^6.13.1", "autoprefixer": "^10.0.1", "dotenv": "^16.4.1", - "eslint": "^8", - "eslint-config-next": "14.0.3", + "eslint": "8.7.0", + "eslint-config-next": "13.4.19", "postcss": "^8", "tailwindcss": "^3.3.0", "typescript": "^5" @@ -114,39 +114,15 @@ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", + "espree": "^9.4.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -161,15 +137,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@ethereumjs/rlp": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", @@ -956,36 +923,23 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.5" + "minimatch": "^3.0.4" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "node_modules/@ioredis/commands": { @@ -1164,9 +1118,9 @@ "integrity": "sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA==" }, "node_modules/@next/eslint-plugin-next": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.0.3.tgz", - "integrity": "sha512-j4K0n+DcmQYCVnSAM+UByTVfIHnYQy2ODozfQP+4RdwtRDfobrIvKq1K4Exb2koJ79HSSa7s6B2SA8T/1YR3RA==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.19.tgz", + "integrity": "sha512-N/O+zGb6wZQdwu6atMZHbR7T9Np5SUFUjZqCbj0sXm+MwQO35M8TazVB4otm87GkXYs2l6OPwARd3/PUWhZBVQ==", "dev": true, "dependencies": { "glob": "7.1.7" @@ -2518,12 +2472,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vanilla-extract/css": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.1.tgz", @@ -4542,49 +4490,46 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz", + "integrity": "sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.0.5", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^7.1.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.2.0", + "espree": "^9.3.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", "ignore": "^5.2.0", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.0.4", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "bin": { "eslint": "bin/eslint.js" @@ -4597,19 +4542,19 @@ } }, "node_modules/eslint-config-next": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.0.3.tgz", - "integrity": "sha512-IKPhpLdpSUyKofmsXUfrvBC49JMUTdeaD8ZIH4v9Vk0sC1X6URTuTJCLtA0Vwuj7V/CQh0oISuSTvNn5//Buew==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.19.tgz", + "integrity": "sha512-WE8367sqMnjhWHvR5OivmfwENRQ1ixfNE9hZwQqNCsd+iM3KnuMc1V8Pt6ytgjxjf23D+xbesADv9x3xaKfT3g==", "dev": true, "dependencies": { - "@next/eslint-plugin-next": "14.0.3", - "@rushstack/eslint-patch": "^1.3.3", + "@next/eslint-plugin-next": "13.4.19", + "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.33.2", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.31.7", "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" }, "peerDependencies": { @@ -5308,22 +5253,6 @@ "node": ">=0.10.0" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -5442,6 +5371,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -5563,9 +5498,9 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -5640,12 +5575,6 @@ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/h3": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/h3/-/h3-1.10.1.tgz", @@ -6170,15 +6099,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6712,21 +6632,6 @@ "@types/trusted-types": "^2.0.2" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -7395,36 +7300,6 @@ "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz", "integrity": "sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==" }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -9318,6 +9193,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, "node_modules/valtio": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.11.2.tgz", @@ -10198,18 +10079,6 @@ "node": ">=8" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { "version": "3.22.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", diff --git a/package.json b/package.json index 8bdc28d5..ab9f9c1d 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint --config .eslintrc" }, "dependencies": { "@headlessui-float/react": "^0.13.0", @@ -39,8 +39,8 @@ "@typescript-eslint/parser": "^6.13.1", "autoprefixer": "^10.0.1", "dotenv": "^16.4.1", - "eslint": "^8", - "eslint-config-next": "14.0.3", + "eslint": "8.7.0", + "eslint-config-next": "13.4.19", "postcss": "^8", "tailwindcss": "^3.3.0", "typescript": "^5" From d4398396427e5e796ddd3f3058e303d8b115309c Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 21:09:08 -0300 Subject: [PATCH 093/305] feat: add padding search-bar --- components/01-atoms/SearchBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 6c6e4aa1..a50ab7dc 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -80,7 +80,7 @@ export const SearchBar = () => { }, [loadingENSaddress]); return ( -
+

Who are you swapping with today? From 4921fa811eeb3f31baada33735b2a339f2b334a0 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 19 Feb 2024 21:30:43 -0300 Subject: [PATCH 094/305] feat: add 0xneves CODEOWNER --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index b0269319..b0c0ffc7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,3 @@ # Default owners for everything in the repo -* @FrancoAguzzi @heronlancellot @eduramme +- @FrancoAguzzi @heronlancellot @eduramme @0xneves From b88e778cb1d85459b303361c0ab1fcfe9749336e Mon Sep 17 00:00:00 2001 From: eduramme Date: Tue, 20 Feb 2024 13:11:35 -0300 Subject: [PATCH 095/305] remove 'connect wallet' text --- components/02-molecules/TheHeader.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 28e6b494..7e966132 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -17,20 +17,9 @@ import Link from "next/link"; import cc from "classcat"; export const TheHeader = () => { - const { isDesktop } = useScreenSize(); const { authenticatedUserAddress } = useAuthenticatedUser(); - const [showFullNav, setShowFullNav] = useState( - !isDesktop && !!authenticatedUserAddress?.address, - ); - const { toggleSidebar, isSidebarOpen } = useSidebar(); - const { isWideScreen } = useScreenSize(); - - useEffect(() => { - setShowFullNav(!isDesktop); - }, [isDesktop]); - const { systemTheme, theme, setTheme } = useTheme(); const [mounted, setMounted] = useState(false); @@ -52,9 +41,6 @@ export const TheHeader = () => { fill={cc([theme == "dark" ? "#DDF23D" : "#4F4F4F"])} /> -
- -

From 454b9cd21ad1445336c44f191e227ad440a28031 Mon Sep 17 00:00:00 2001 From: eduramme Date: Tue, 20 Feb 2024 13:14:51 -0300 Subject: [PATCH 096/305] resolve requested changes --- components/01-atoms/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index fb04dee6..583c326f 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -21,14 +21,11 @@ export * from "./icons/DangerIcon"; export * from "./icons/EthereumIcon"; export * from "./icons/ErrorIcon"; export * from "./icons/LeftIcon"; -export * from "./icons/MagnifyingGlassIcon"; export * from "./icons/NotificationsIcon"; export * from "./icons/OffersIcon"; -export * from "./icons/PaperPlane"; export * from "./icons/PersonIcon"; export * from "./icons/PolygonIcon"; export * from "./icons/RightIcon"; -export * from "./icons/SelectUserIcon"; export * from "./icons/SwapIcon"; export * from "./icons/SwaplaceIcon"; export * from "./icons/SwappingIcon"; From 73a962b2e8fa190a1d76fb11faa712edd50e15e1 Mon Sep 17 00:00:00 2001 From: eduramme Date: Tue, 20 Feb 2024 14:29:23 -0300 Subject: [PATCH 097/305] create user info component --- components/01-atoms/WalletSidebarTemplate.tsx | 2 ++ components/02-molecules/UserInfo.tsx | 9 +++++++++ components/02-molecules/index.tsx | 1 + 3 files changed, 12 insertions(+) create mode 100644 components/02-molecules/UserInfo.tsx diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index 52f1e277..c8f12aad 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -1,4 +1,5 @@ import { TheSidebarHeader } from "../02-molecules/TheSidebarHeader"; +import { UserInfo } from "../02-molecules"; import React from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; @@ -36,6 +37,7 @@ export const WalletSidebarTemplate = ({ ])} > +
); diff --git a/components/02-molecules/UserInfo.tsx b/components/02-molecules/UserInfo.tsx new file mode 100644 index 00000000..e55caa88 --- /dev/null +++ b/components/02-molecules/UserInfo.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +export const UserInfo = () => { + return ( +
+

User info

+
+ ); +}; diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index cd264179..c2113745 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -8,3 +8,4 @@ export * from "./OfferSummary"; export * from "./ProgressStatus"; export * from "./SwapStation"; export * from "./TheHeader"; +export * from "./UserInfo"; From 9ae9be24c66e9e75905a7772d25fc9df132098c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 20 Feb 2024 15:06:31 -0300 Subject: [PATCH 098/305] feat: add a active status to StatusOffers atom --- components/01-atoms/StatusOffers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/StatusOffers.tsx b/components/01-atoms/StatusOffers.tsx index a5930aa1..8d741e85 100644 --- a/components/01-atoms/StatusOffers.tsx +++ b/components/01-atoms/StatusOffers.tsx @@ -43,7 +43,7 @@ export const StatusOffers = () => { return (
From 509b93bddce493da77b501420c733c12fd279114 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 20 Feb 2024 15:09:30 -0300 Subject: [PATCH 099/305] feat: add layout to display swap offers error & no swaps --- components/01-atoms/icons/NoSwapsIcon.tsx | 88 +++++++++++++++ components/01-atoms/index.ts | 5 +- .../02-molecules/ErrorFindingSwapOffers.tsx | 39 ------- components/02-molecules/SwapOffersLayout.tsx | 103 ++++++++++++++++++ components/02-molecules/index.tsx | 2 +- components/04-templates/OfferSection.tsx | 7 +- 6 files changed, 197 insertions(+), 47 deletions(-) create mode 100644 components/01-atoms/icons/NoSwapsIcon.tsx delete mode 100644 components/02-molecules/ErrorFindingSwapOffers.tsx create mode 100644 components/02-molecules/SwapOffersLayout.tsx diff --git a/components/01-atoms/icons/NoSwapsIcon.tsx b/components/01-atoms/icons/NoSwapsIcon.tsx new file mode 100644 index 00000000..9ff5e0f4 --- /dev/null +++ b/components/01-atoms/icons/NoSwapsIcon.tsx @@ -0,0 +1,88 @@ +import { SVGProps } from "react"; + +export const NoSwapsIcon = (props: SVGProps) => { + return ( + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 5435aa2e..aa8b8f8b 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -8,12 +8,14 @@ export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; export * from "./SelectDestinyChain"; export * from "./StatusOffers"; +export * from "./SwapAddManuallyModalLayout"; export * from "./SwapContext"; export * from "./SwapExpireTime"; export * from "./SwapModalButton"; export * from "./SwappingIcons"; export * from "./Tab"; export * from "./Tooltip"; +export * from "./WalletSidebarTemplate"; export * from "./ENSAvatar"; export * from "./icons/ChatIcon"; export * from "./icons/CheckIcon"; @@ -35,6 +37,5 @@ export * from "./icons/WalletIcon"; export * from "./icons/SunIcon"; export * from "./icons/PaperPlane"; export * from "./icons/MagnifyingGlassIcon"; -export * from "./WalletSidebarTemplate"; export * from "./icons/MoonIcon"; -export * from "./SwapAddManuallyModalLayout"; \ No newline at end of file +export * from "./icons/NoSwapsIcon"; diff --git a/components/02-molecules/ErrorFindingSwapOffers.tsx b/components/02-molecules/ErrorFindingSwapOffers.tsx deleted file mode 100644 index 8bc3d0d6..00000000 --- a/components/02-molecules/ErrorFindingSwapOffers.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { ErrorIcon, SwapAddManuallyModalLayout } from "@/components/01-atoms"; -import cc from "classcat"; -import { useTheme } from "next-themes"; -import { useState } from "react"; - -export const ErrorFindingSwapOffers = () => { - const { theme } = useTheme(); - const [toggleManually, setToggleManually] = useState(false); - return ( -
-
- -
-
-

- Sorry, we couldn't load your swaps -

-

- Please try again later or add your swaps manually -

-
-
- - { - setToggleManually(false); - }} - variant="swap" - /> -
-
- ); -}; diff --git a/components/02-molecules/SwapOffersLayout.tsx b/components/02-molecules/SwapOffersLayout.tsx new file mode 100644 index 00000000..9f7e7c12 --- /dev/null +++ b/components/02-molecules/SwapOffersLayout.tsx @@ -0,0 +1,103 @@ +import { + ErrorIcon, + NoSwapsIcon, + SwapAddManuallyModalLayout, +} from "@/components/01-atoms"; +import { useTheme } from "next-themes"; +import React, { useState } from "react"; +import cc from "classcat"; +import { useRouter } from "next/router"; + +interface EmptyLayoutOffersProps { + icon: React.ReactNode; + title: React.ReactNode; + description: React.ReactNode; + button: React.ReactNode; +} + +const EmptyLayoutOffers = ({ + icon, + title, + description, + button, +}: EmptyLayoutOffersProps) => { + return ( +
+
{icon}
+
+

+ {title} +

+

+ {description} +

+
+
{button}
+
+ ); +}; + +export enum SwapOffersDisplayVariant { + ERROR = "error", + NO_SWAPS_CREATED = "swapless", +} + +type Variant = SwapOffersDisplayVariant | "error" | "swapless"; + +interface SwapOffersLayoutProps { + variant: Variant; +} + +export const SwapOffersLayout = ({ variant }: SwapOffersLayoutProps) => { + const { theme } = useTheme(); + const [toggleManually, setToggleManually] = useState(false); + const router = useRouter(); + + return ( + <> + {variant === SwapOffersDisplayVariant.ERROR ? ( + } + title={<> Sorry, we couldn't load your swaps} + description={<> Please try again later or add your swaps manually} + button={ + <> + + { + setToggleManually(false); + }} + variant="swap" + /> + + } + /> + ) : ( + } + title={<> No swaps here. Let's fill it up!} + description={ +
+ You haven't made or received any proposals. Time to jump in + and start trading. +
+ } + button={ + + } + /> + )} + + ); +}; diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index cd264179..8859600b 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -1,10 +1,10 @@ export * from "./CardHome"; export * from "./ConfirmSwapModal"; -export * from "./ErrorFindingSwapOffers"; export * from "./FilterOffers"; export * from "./NftCard"; export * from "./NftsList"; export * from "./OfferSummary"; +export * from "./SwapOffersLayout"; export * from "./ProgressStatus"; export * from "./SwapStation"; export * from "./TheHeader"; diff --git a/components/04-templates/OfferSection.tsx b/components/04-templates/OfferSection.tsx index 7c6eccb0..de19f884 100644 --- a/components/04-templates/OfferSection.tsx +++ b/components/04-templates/OfferSection.tsx @@ -1,7 +1,4 @@ -import { - ErrorFindingSwapOffers, - FilterOffers, -} from "@/components/02-molecules"; +import { FilterOffers, SwapOffersLayout } from "@/components/02-molecules"; export const OfferSection = () => { return ( @@ -10,7 +7,7 @@ export const OfferSection = () => {
- +
); From 91c96cec7a9f2c93508d78121f7e9114adbbe53c Mon Sep 17 00:00:00 2001 From: eduramme Date: Tue, 20 Feb 2024 15:10:34 -0300 Subject: [PATCH 100/305] display address and basic user info --- components/01-atoms/WalletSidebarTemplate.tsx | 8 +-- components/01-atoms/icons/CopyIcon.tsx | 19 +++++++ .../01-atoms/icons/ExternalLinkIcon.tsx | 19 +++++++ components/01-atoms/index.ts | 4 +- .../02-molecules/EnsNameAndAddressWallet.tsx | 54 +++++++++++++++++++ components/02-molecules/TheSidebarHeader.tsx | 2 +- components/02-molecules/UserInfo.tsx | 16 +++++- lib/client/utils.ts | 16 ++++++ 8 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 components/01-atoms/icons/CopyIcon.tsx create mode 100644 components/01-atoms/icons/ExternalLinkIcon.tsx create mode 100644 components/02-molecules/EnsNameAndAddressWallet.tsx diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index c8f12aad..1605af7f 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -28,7 +28,7 @@ export const WalletSidebarTemplate = ({
- - +
+ + +
); diff --git a/components/01-atoms/icons/CopyIcon.tsx b/components/01-atoms/icons/CopyIcon.tsx new file mode 100644 index 00000000..bcd3f787 --- /dev/null +++ b/components/01-atoms/icons/CopyIcon.tsx @@ -0,0 +1,19 @@ +import React, { SVGProps } from "react"; + +export const CopyIcon = (props: SVGProps) => { + return ( + + + + ); +}; diff --git a/components/01-atoms/icons/ExternalLinkIcon.tsx b/components/01-atoms/icons/ExternalLinkIcon.tsx new file mode 100644 index 00000000..537433f7 --- /dev/null +++ b/components/01-atoms/icons/ExternalLinkIcon.tsx @@ -0,0 +1,19 @@ +import React, { SVGProps } from "react"; + +export const ExternalLinkIcon = (props: SVGProps) => { + return ( + + + + ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 5435aa2e..bc196ea3 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -32,8 +32,10 @@ export * from "./icons/SwaplaceIcon"; export * from "./icons/SwappingIcon"; export * from "./icons/XMarkIcon"; export * from "./icons/WalletIcon"; -export * from "./icons/SunIcon"; export * from "./icons/PaperPlane"; +export * from "./icons/ExternalLinkIcon"; +export * from "./icons/SunIcon"; +export * from "./icons/CopyIcon"; export * from "./icons/MagnifyingGlassIcon"; export * from "./WalletSidebarTemplate"; export * from "./icons/MoonIcon"; diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx new file mode 100644 index 00000000..411272c4 --- /dev/null +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -0,0 +1,54 @@ +import { CopyIcon, ENSAvatar, ExternalLinkIcon } from "../01-atoms"; +import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import { useEnsData } from "@/lib/client/hooks/useENSData"; +import { collapseAddress } from "@/lib/client/utils"; +import React from "react"; + +export const EnsNameAndAddressWallet = () => { + const { authenticatedUserAddress } = useAuthenticatedUser(); + + const { avatarQueryStatus, avatarSrc, primaryName } = useEnsData({ + ensAddress: authenticatedUserAddress, + }); + + console.log("avatarQueryStatus ", avatarQueryStatus); + console.log("avatarSrc ", avatarSrc); + console.log("primaryName ", primaryName); + + const displayAddress = + collapseAddress(authenticatedUserAddress?.toString() ?? "") || ""; + + return ( +
+ {authenticatedUserAddress && ( + <> + + +
+
+ {primaryName && ( +

{`${primaryName} | `}

+ )} +
+

{displayAddress}

+ +
+
+
+

+ View on explorer +

+ +
+
+ + )} +
+ ); +}; diff --git a/components/02-molecules/TheSidebarHeader.tsx b/components/02-molecules/TheSidebarHeader.tsx index 30bfd454..2a0632b7 100644 --- a/components/02-molecules/TheSidebarHeader.tsx +++ b/components/02-molecules/TheSidebarHeader.tsx @@ -13,7 +13,7 @@ export const TheSidebarHeader = () => { return ( -
+
-
-

+
+

View on explorer

- +
+ +

diff --git a/components/02-molecules/UserInfo.tsx b/components/02-molecules/UserInfo.tsx index d643bf74..85a29c14 100644 --- a/components/02-molecules/UserInfo.tsx +++ b/components/02-molecules/UserInfo.tsx @@ -1,22 +1,17 @@ -import { EnsNameAndAddressWallet } from "./EnsNameAndAddressWallet"; +import { EnsNameAndAddressWallet } from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useEnsData } from "@/lib/client/hooks/useENSData"; import React from "react"; export const UserInfo = () => { - const { authenticatedUserAddress } = useAuthenticatedUser(); - const { avatarQueryStatus, avatarSrc, primaryName } = useEnsData({ + useEnsData({ ensAddress: authenticatedUserAddress, }); - console.log("avatarQueryStatus ", avatarQueryStatus) - console.log("avatarSrc ", avatarSrc) - console.log("primaryName ", primaryName) - return ( -
+
); diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index c2113745..4608a734 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -1,5 +1,6 @@ export * from "./CardHome"; export * from "./ConfirmSwapModal"; +export * from "./EnsNameAndAddressWallet"; export * from "./ErrorFindingSwapOffers"; export * from "./FilterOffers"; export * from "./NftCard"; @@ -8,4 +9,5 @@ export * from "./OfferSummary"; export * from "./ProgressStatus"; export * from "./SwapStation"; export * from "./TheHeader"; +export * from "./TheSidebarHeader"; export * from "./UserInfo"; From ff722f83d70e323bcb89e73e27a4fe6fc3aab4a1 Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 21 Feb 2024 14:00:38 -0300 Subject: [PATCH 105/305] create block explorer link --- components/02-molecules/EnsNameAndAddressWallet.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx index c8056b2d..4b35a240 100644 --- a/components/02-molecules/EnsNameAndAddressWallet.tsx +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -6,20 +6,23 @@ import React from "react"; export const EnsNameAndAddressWallet = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); + const stringAddress = authenticatedUserAddress?.toString() const { primaryName } = useEnsData({ ensAddress: authenticatedUserAddress, }); + const blockExplorer = `https://etherscan.io/address/${stringAddress}` + + const displayAddress = - collapseAddress(authenticatedUserAddress?.toString() ?? "") || ""; + collapseAddress(stringAddress ?? "") || ""; return (
{authenticatedUserAddress && ( <> -
{primaryName && ( @@ -45,14 +48,14 @@ export const EnsNameAndAddressWallet = () => {
- +
)} From f3b0f7fdbd7eb3f5fd614a3cc5652b40302b122c Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 21 Feb 2024 15:52:34 -0300 Subject: [PATCH 106/305] create balance status --- components/01-atoms/ENSAvatar.tsx | 1 - .../AccountBalanceWalletSidebar.tsx | 28 ++++++++++ .../02-molecules/EnsNameAndAddressWallet.tsx | 2 +- components/02-molecules/UserInfo.tsx | 2 + components/02-molecules/index.tsx | 1 + lib/client/hooks/useWalletBalance.tsx | 52 +++++++++++++++++++ lib/client/utils.ts | 19 ++++++- 7 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 components/02-molecules/AccountBalanceWalletSidebar.tsx create mode 100644 lib/client/hooks/useWalletBalance.tsx diff --git a/components/01-atoms/ENSAvatar.tsx b/components/01-atoms/ENSAvatar.tsx index 742f4d91..aefabe4b 100644 --- a/components/01-atoms/ENSAvatar.tsx +++ b/components/01-atoms/ENSAvatar.tsx @@ -67,7 +67,6 @@ export const ENSAvatar = ({ avatarSrc ? ( {`ENS diff --git a/components/02-molecules/AccountBalanceWalletSidebar.tsx b/components/02-molecules/AccountBalanceWalletSidebar.tsx new file mode 100644 index 00000000..e40f528f --- /dev/null +++ b/components/02-molecules/AccountBalanceWalletSidebar.tsx @@ -0,0 +1,28 @@ +import { useWalletBalance } from "@/lib/client/hooks/useWalletBalance"; +import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import React from "react"; +import cc from "classcat"; +import { useTheme } from "next-themes"; + +export const AccountBalanceWalletSidebar = () => { + const { authenticatedUserAddress } = useAuthenticatedUser(); + + + const { systemTheme, theme } = useTheme(); + const currentTheme = theme === "system" ? systemTheme : theme; + const isDark = currentTheme === "dark"; + + const { balance } = useWalletBalance({ + walletAddress: authenticatedUserAddress, + }); + + return ( +
+

Current balance

+
+

{balance}

+

ETH

+
+
+ ); +}; diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx index c8056b2d..14bb04cc 100644 --- a/components/02-molecules/EnsNameAndAddressWallet.tsx +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -15,7 +15,7 @@ export const EnsNameAndAddressWallet = () => { collapseAddress(authenticatedUserAddress?.toString() ?? "") || ""; return ( -
+
{authenticatedUserAddress && ( <> diff --git a/components/02-molecules/UserInfo.tsx b/components/02-molecules/UserInfo.tsx index 85a29c14..af805f7e 100644 --- a/components/02-molecules/UserInfo.tsx +++ b/components/02-molecules/UserInfo.tsx @@ -1,3 +1,4 @@ +import { AccountBalanceWalletSidebar } from "./AccountBalanceWalletSidebar"; import { EnsNameAndAddressWallet } from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useEnsData } from "@/lib/client/hooks/useENSData"; @@ -13,6 +14,7 @@ export const UserInfo = () => { return (
+
); }; diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index f1bb8029..1ca67ed3 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -11,3 +11,4 @@ export * from "./SwapStation"; export * from "./TheHeader"; export * from "./TheSidebarHeader"; export * from "./UserInfo"; +export * from "./AccountBalanceWalletSidebar"; diff --git a/lib/client/hooks/useWalletBalance.tsx b/lib/client/hooks/useWalletBalance.tsx new file mode 100644 index 00000000..8cba07be --- /dev/null +++ b/lib/client/hooks/useWalletBalance.tsx @@ -0,0 +1,52 @@ +import { weiToEther } from "../utils"; +import { EthereumAddress } from "@/lib/shared/types"; +import { useEffect, useState } from "react"; +import { createPublicClient, http } from "viem"; +import { mainnet } from "viem/chains"; + +export enum WalletBalanceQueryStatus { + LOADING, + SUCCESS, + ERROR, +} + +interface Props { + walletAddress: EthereumAddress | null; +} + +export const useWalletBalance = ({ walletAddress }: Props) => { + const [balance, setBalance] = useState(null); + const [balanceQueryStatus, setBalanceQueryStatus] = useState(WalletBalanceQueryStatus.LOADING); + + useEffect(() => { + if (walletAddress) { + const mainnetClient = createPublicClient({ + chain: mainnet, + transport: http(), + }); + + setBalanceQueryStatus(WalletBalanceQueryStatus.LOADING); + + mainnetClient + .getBalance({ + address: walletAddress.address as `0x${string}`, + }) + .then((fetchedBalance) => { + setBalanceQueryStatus(WalletBalanceQueryStatus.SUCCESS); + setBalance(weiToEther(fetchedBalance)); + }) + .catch(() => { + setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); + setBalance(null); + }); + } else { + setBalance(null); + setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); + } + }, [walletAddress]); + + return { + balance, + balanceQueryStatus, + }; +}; diff --git a/lib/client/utils.ts b/lib/client/utils.ts index e431bfd9..36cfddb5 100644 --- a/lib/client/utils.ts +++ b/lib/client/utils.ts @@ -37,4 +37,21 @@ export const collapseAddress = (address: string, startLength = 4, endLength = 4) const collapsedAddress = `0x${start}...${end}`; return collapsedAddress; -} \ No newline at end of file +} + +export const weiToEther = (weiBalance: bigint) => { + const weiString = weiBalance.toString(); + // Ensure the balance has at least 18 characters, padding with zeros if necessary, to represent the wei accurately + const paddedWeiString = weiString.padStart(19, '0'); // Pad to ensure we always have an 18+ digit string + const etherPart = paddedWeiString.slice(0, -18); + const fractionalPart = paddedWeiString.slice(-18); + + // Convert fractional part into a number, divide by 10^18 to get the actual value, then round to 3 decimal places + const fractionalNumber = parseFloat(fractionalPart) / 1e18; + const roundedFractionalPart = fractionalNumber.toFixed(3).slice(2); // Get the rounded fractional part as a string without the '0.' prefix + + // Concatenate the ether part with the rounded fractional part, adding a decimal point only if fractional part is non-zero + const result = etherPart + (roundedFractionalPart !== '000' ? '.' + roundedFractionalPart : ''); + + return result; +}; From 2ad62d99f00b7cf621f5502bcebe8d0420731d78 Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 21 Feb 2024 16:42:38 -0300 Subject: [PATCH 107/305] create balance for connected chain --- .../AccountBalanceWalletSidebar.tsx | 9 +++++++-- lib/client/hooks/useWalletBalance.tsx | 19 ++++++++++--------- lib/client/utils.ts | 19 +------------------ 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/components/02-molecules/AccountBalanceWalletSidebar.tsx b/components/02-molecules/AccountBalanceWalletSidebar.tsx index e40f528f..d986ad03 100644 --- a/components/02-molecules/AccountBalanceWalletSidebar.tsx +++ b/components/02-molecules/AccountBalanceWalletSidebar.tsx @@ -3,10 +3,12 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import React from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; +import { useNetwork } from "wagmi"; export const AccountBalanceWalletSidebar = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); + const { chain } = useNetwork(); const { systemTheme, theme } = useTheme(); const currentTheme = theme === "system" ? systemTheme : theme; @@ -16,12 +18,15 @@ export const AccountBalanceWalletSidebar = () => { walletAddress: authenticatedUserAddress, }); + const match = balance?.match(/^(\d+\.\d{1,3})|\d+/); + const displayBalance = match ? match[0] : balance; + return (

Current balance

-

{balance}

-

ETH

+

{displayBalance}

+

{chain?.nativeCurrency.symbol}

); diff --git a/lib/client/hooks/useWalletBalance.tsx b/lib/client/hooks/useWalletBalance.tsx index 8cba07be..2fb16526 100644 --- a/lib/client/hooks/useWalletBalance.tsx +++ b/lib/client/hooks/useWalletBalance.tsx @@ -1,8 +1,7 @@ -import { weiToEther } from "../utils"; import { EthereumAddress } from "@/lib/shared/types"; import { useEffect, useState } from "react"; -import { createPublicClient, http } from "viem"; -import { mainnet } from "viem/chains"; +import { createPublicClient, formatUnits, http } from "viem"; +import { useNetwork } from "wagmi"; export enum WalletBalanceQueryStatus { LOADING, @@ -18,22 +17,24 @@ export const useWalletBalance = ({ walletAddress }: Props) => { const [balance, setBalance] = useState(null); const [balanceQueryStatus, setBalanceQueryStatus] = useState(WalletBalanceQueryStatus.LOADING); + const { chain } = useNetwork(); + useEffect(() => { - if (walletAddress) { - const mainnetClient = createPublicClient({ - chain: mainnet, + if (walletAddress && chain) { + const client = createPublicClient({ + chain: chain, transport: http(), }); setBalanceQueryStatus(WalletBalanceQueryStatus.LOADING); - mainnetClient + client .getBalance({ address: walletAddress.address as `0x${string}`, }) .then((fetchedBalance) => { setBalanceQueryStatus(WalletBalanceQueryStatus.SUCCESS); - setBalance(weiToEther(fetchedBalance)); + !!chain && setBalance(formatUnits(fetchedBalance, chain.nativeCurrency.decimals)); }) .catch(() => { setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); @@ -43,7 +44,7 @@ export const useWalletBalance = ({ walletAddress }: Props) => { setBalance(null); setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); } - }, [walletAddress]); + }, [walletAddress, chain]); return { balance, diff --git a/lib/client/utils.ts b/lib/client/utils.ts index 36cfddb5..e431bfd9 100644 --- a/lib/client/utils.ts +++ b/lib/client/utils.ts @@ -37,21 +37,4 @@ export const collapseAddress = (address: string, startLength = 4, endLength = 4) const collapsedAddress = `0x${start}...${end}`; return collapsedAddress; -} - -export const weiToEther = (weiBalance: bigint) => { - const weiString = weiBalance.toString(); - // Ensure the balance has at least 18 characters, padding with zeros if necessary, to represent the wei accurately - const paddedWeiString = weiString.padStart(19, '0'); // Pad to ensure we always have an 18+ digit string - const etherPart = paddedWeiString.slice(0, -18); - const fractionalPart = paddedWeiString.slice(-18); - - // Convert fractional part into a number, divide by 10^18 to get the actual value, then round to 3 decimal places - const fractionalNumber = parseFloat(fractionalPart) / 1e18; - const roundedFractionalPart = fractionalNumber.toFixed(3).slice(2); // Get the rounded fractional part as a string without the '0.' prefix - - // Concatenate the ether part with the rounded fractional part, adding a decimal point only if fractional part is non-zero - const result = etherPart + (roundedFractionalPart !== '000' ? '.' + roundedFractionalPart : ''); - - return result; -}; +} \ No newline at end of file From 69ffcdf5b06966a51394ce6e9c9d01df48900745 Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 21 Feb 2024 16:50:39 -0300 Subject: [PATCH 108/305] get default explorer address --- .../02-molecules/EnsNameAndAddressWallet.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx index 4b35a240..ac9f5006 100644 --- a/components/02-molecules/EnsNameAndAddressWallet.tsx +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -3,20 +3,21 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useEnsData } from "@/lib/client/hooks/useENSData"; import { collapseAddress } from "@/lib/client/utils"; import React from "react"; +import { useNetwork } from "wagmi"; export const EnsNameAndAddressWallet = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); - const stringAddress = authenticatedUserAddress?.toString() + const stringAddress = authenticatedUserAddress?.toString(); const { primaryName } = useEnsData({ ensAddress: authenticatedUserAddress, }); - const blockExplorer = `https://etherscan.io/address/${stringAddress}` + const { chain } = useNetwork(); + const blockExplorer = `${chain?.blockExplorers?.default.url}/address/${stringAddress}`; - const displayAddress = - collapseAddress(stringAddress ?? "") || ""; + const displayAddress = collapseAddress(stringAddress ?? "") || ""; return (
@@ -48,7 +49,11 @@ export const EnsNameAndAddressWallet = () => {
- +

View on explorer

From 9f84d4813d69e27d2207920ea073326f94b61a20 Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 21 Feb 2024 19:32:34 -0300 Subject: [PATCH 109/305] feat: Offer Expiry Confirm Swap Atom --- .../01-atoms/OfferExpiryConfirmSwap.tsx | 24 +++++++++++++++++++ components/01-atoms/index.ts | 1 + components/02-molecules/ConfirmSwapModal.tsx | 7 +++--- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 components/01-atoms/OfferExpiryConfirmSwap.tsx diff --git a/components/01-atoms/OfferExpiryConfirmSwap.tsx b/components/01-atoms/OfferExpiryConfirmSwap.tsx new file mode 100644 index 00000000..5e3bdc91 --- /dev/null +++ b/components/01-atoms/OfferExpiryConfirmSwap.tsx @@ -0,0 +1,24 @@ +interface OfferExpiryConfirmSwapProps { + expireTime: string; +} + +export const OfferExpiryConfirmSwap = ({ + expireTime +}: OfferExpiryConfirmSwapProps) => { + return ( + <> +
+

+ Offer expires in +

+

+ {expireTime} +

+
+ + ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 31009ed0..e02e43d2 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -2,6 +2,7 @@ export * from "./SwapModalLayout"; export * from "./ConnectWallet"; export * from "./EmptyNftsCards"; export * from "./LoadingIndicator"; +export * from "./OfferExpiryConfirmSwap"; export * from "./NftsCardApprovedList"; export * from "./ProgressBar"; export * from "./SearchBar"; diff --git a/components/02-molecules/ConfirmSwapModal.tsx b/components/02-molecules/ConfirmSwapModal.tsx index ddb5b5a5..461df4a0 100644 --- a/components/02-molecules/ConfirmSwapModal.tsx +++ b/components/02-molecules/ConfirmSwapModal.tsx @@ -6,6 +6,7 @@ import { SwapContext, SwapModalButton, SwapModalLayout, + OfferExpiryConfirmSwap } from "@/components/01-atoms"; import { ProgressStatus } from "@/components/02-molecules"; import { createSwap } from "@/lib/service/createSwap"; @@ -173,7 +174,7 @@ export const ConfirmSwapModal = ({ description: "Please review your final proposal.", }} body={{ - component: "", + component: , }} footer={{ component: ( @@ -209,7 +210,7 @@ export const ConfirmSwapModal = ({ description: "Please review your final proposal.", }} body={{ - component: "", + component: , }} footer={{ component: ( @@ -235,7 +236,7 @@ export const ConfirmSwapModal = ({ description: "Congrats, your swap offer was submitted.", }} body={{ - component: "", + component: , }} footer={{ component: ( From 9aef83c91894a8ef6382c7c4430d24756ee91049 Mon Sep 17 00:00:00 2001 From: eduramme Date: Thu, 22 Feb 2024 10:00:53 -0300 Subject: [PATCH 110/305] fix copy paste address button --- .../02-molecules/EnsNameAndAddressWallet.tsx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx index ac9f5006..e9798d1a 100644 --- a/components/02-molecules/EnsNameAndAddressWallet.tsx +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -34,20 +34,21 @@ export const EnsNameAndAddressWallet = () => { )} -
+ -
+
+
Date: Thu, 22 Feb 2024 10:18:58 -0300 Subject: [PATCH 111/305] update: import to @/components --- components/02-molecules/UserInfo.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/02-molecules/UserInfo.tsx b/components/02-molecules/UserInfo.tsx index af805f7e..c2af8dd6 100644 --- a/components/02-molecules/UserInfo.tsx +++ b/components/02-molecules/UserInfo.tsx @@ -1,5 +1,7 @@ -import { AccountBalanceWalletSidebar } from "./AccountBalanceWalletSidebar"; -import { EnsNameAndAddressWallet } from "@/components/02-molecules"; +import { + AccountBalanceWalletSidebar, + EnsNameAndAddressWallet, +} from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useEnsData } from "@/lib/client/hooks/useENSData"; import React from "react"; @@ -14,7 +16,7 @@ export const UserInfo = () => { return (
- +
); }; From e296191890fef6c2e308b641ccce0bb0045f42c3 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Thu, 22 Feb 2024 16:38:37 -0300 Subject: [PATCH 112/305] feat: add token card properties --- components/01-atoms/TokenCardProperties.tsx | 28 +++++++++++++++++++++ components/01-atoms/index.ts | 2 ++ 2 files changed, 30 insertions(+) create mode 100644 components/01-atoms/TokenCardProperties.tsx diff --git a/components/01-atoms/TokenCardProperties.tsx b/components/01-atoms/TokenCardProperties.tsx new file mode 100644 index 00000000..3c9ba79a --- /dev/null +++ b/components/01-atoms/TokenCardProperties.tsx @@ -0,0 +1,28 @@ +interface PropertiesInfo { + amount: number; + value: number; +} + +interface TokenCardPropertiesProps { + properties: PropertiesInfo; +} + +export const TokenCardProperties = ({ + properties, +}: TokenCardPropertiesProps) => { + return ( +
+
+
{properties.amount} item(s)
+
+

+ {properties.value} ETH +

+

+   ($){properties.value} +

+
+
+
+ ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index e02e43d2..4cad38c6 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -13,8 +13,10 @@ export * from "./SwapAddManuallyModalLayout"; export * from "./SwapContext"; export * from "./SwapExpireTime"; export * from "./SwapModalButton"; +export * from "./SwapOfferDetails"; export * from "./SwappingIcons"; export * from "./Tab"; +export * from "./TokenCardProperties"; export * from "./Tooltip"; export * from "./WalletSidebarTemplate"; export * from "./ENSAvatar"; From 4ee2d166084a0392cf562798f32090d826807ae3 Mon Sep 17 00:00:00 2001 From: 0xneves Date: Fri, 23 Feb 2024 03:41:22 +0700 Subject: [PATCH 113/305] docs: cleared instructions on README.md --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ef85d40b..83d47258 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ This repository contains the core frontend for the Swaplace Protocol; The lighte ## Setup -First, install the dependences: +ATTENTION: After cloning the repository, you must change the branch into the `develop` branch to get the latest version. +WARNING: `main` branch is not stable at the moment. + +You should install the dependencies using legacy mode and then run the development server. ```bash npm i --legacy-peer-deps @@ -24,25 +27,23 @@ bun dev ### Environment Variables -The project comes with a `.env.example` file. You should rename it to `.env` and fill the variables with your values. Most RPC providers offer free testnet nodes. You can use [Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/) to get a free node. +The project comes with a `.env.example` file. You should rename it to `.env` and fill the variables with your values. Most RPC providers offer free testnet nodes. You can use [Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/) to get a free node. We are currently using Sepolia for testing purposes but you can use any other provider and evm chains to test the application. + +Alchemy has two types of keys, one for the HTTP provider and another for the Alchemy SDK. You should use the HTTP key for the `NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP` variable and the SDK key for the `NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY` variable. + +The HTTP key is used to connect to the blockchain and the SDK key is used to connect to the Alchemy API, which allows us to get the user custody tokens easily. ``` NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= -NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= -NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY= -NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= ``` -WARNING: The private keys used in the `.env` file are from hardhat accounts. They are not meant to be used in production. - WARNING: The `NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=` used in the `.env` file is public. They are not meant to be used in production. -If you want use your own please create your Project ID in the [WalletConnect](https://cloud.walletconnect.com/) +If you want use your own please create your Project ID in the [WalletConnect](https://cloud.walletconnect.com/) website (not mandatory). ``` NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= - ``` ## Contributing From b478a361f32b725c3c04ab724c6d9002a667280a Mon Sep 17 00:00:00 2001 From: "heronlancellot.eth" Date: Thu, 22 Feb 2024 18:04:30 -0300 Subject: [PATCH 114/305] Update README.md - change cloning to forking --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83d47258..77b0413c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository contains the core frontend for the Swaplace Protocol; The lighte ## Setup -ATTENTION: After cloning the repository, you must change the branch into the `develop` branch to get the latest version. +ATTENTION: After forking the repository, you must change the branch into the `develop` branch to get the latest version. WARNING: `main` branch is not stable at the moment. You should install the dependencies using legacy mode and then run the development server. From aefee2a9e753bf82608075a51d4723c3bee2c2f8 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 12:51:41 -0300 Subject: [PATCH 115/305] feat: add TokensOfferSkeleton --- components/01-atoms/TokensOfferSkeleton.tsx | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 components/01-atoms/TokensOfferSkeleton.tsx diff --git a/components/01-atoms/TokensOfferSkeleton.tsx b/components/01-atoms/TokensOfferSkeleton.tsx new file mode 100644 index 00000000..a79b19b6 --- /dev/null +++ b/components/01-atoms/TokensOfferSkeleton.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import cc from "classcat"; + +export const TokensOfferSkeleton = () => { + const TokenCardSkeleton = () => { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); + }; + + const SwapOfferDetailsSkeleton = () => { + return ( +
+
+
+
+
+
+
+
+
+
+
+ ); + }; + + return ( +
+
+
+ +
+
+ +
+
+ +
+ ); +}; From 3e5fe50c8f296d1ab7ae7708a9a012a17767ff09 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 12:57:39 -0300 Subject: [PATCH 116/305] feat: add Offer Tag Component --- components/01-atoms/OfferTag.tsx | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 components/01-atoms/OfferTag.tsx diff --git a/components/01-atoms/OfferTag.tsx b/components/01-atoms/OfferTag.tsx new file mode 100644 index 00000000..7e1f2783 --- /dev/null +++ b/components/01-atoms/OfferTag.tsx @@ -0,0 +1,32 @@ +export const OfferTag = () => { + enum TAG { + PEDING = "PENDING", + ACCEPTED = "ACCEPTED", + CANCELED = "CANCELED", + EXPIRED = "EXPIRED", + } + interface TagConfig { + body: React.ReactNode; + } + + const Tags: Record = { + [TAG.ACCEPTED]: { + body:
{TAG.ACCEPTED}
, + }, + [TAG.CANCELED]: { + body:
{TAG.CANCELED}
, + }, + [TAG.EXPIRED]: { + body:
{TAG.EXPIRED}
, + }, + [TAG.PEDING]: { + body:
{TAG.PEDING}
, + }, + }; + + return ( +
+ {Tags[TAG.PEDING].body} +
+ ); +}; From a75511eae716d2cc1e876d2ae8f6a4e92674f12e Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 13:11:33 -0300 Subject: [PATCH 117/305] feat: add three dots card offers options --- .../01-atoms/ThreeDotsCardOffersOptions.tsx | 56 +++++++++++++++++++ components/01-atoms/icons/CheckIcon.tsx | 22 -------- components/01-atoms/icons/DoneIcon.tsx | 22 ++++++++ components/01-atoms/icons/ShareIcon.tsx | 22 ++++++++ components/01-atoms/icons/ThreeDotsIcon.tsx | 20 +++++++ components/01-atoms/index.ts | 8 ++- 6 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 components/01-atoms/ThreeDotsCardOffersOptions.tsx delete mode 100644 components/01-atoms/icons/CheckIcon.tsx create mode 100644 components/01-atoms/icons/DoneIcon.tsx create mode 100644 components/01-atoms/icons/ShareIcon.tsx create mode 100644 components/01-atoms/icons/ThreeDotsIcon.tsx diff --git a/components/01-atoms/ThreeDotsCardOffersOptions.tsx b/components/01-atoms/ThreeDotsCardOffersOptions.tsx new file mode 100644 index 00000000..3e62d9bf --- /dev/null +++ b/components/01-atoms/ThreeDotsCardOffersOptions.tsx @@ -0,0 +1,56 @@ +import { ShareIcon, ThreeDotsIcon, XMarkIcon } from "@/components/01-atoms"; +import { useState } from "react"; +import cc from "classcat"; + +export const ThreeDotsCardOffersOptions = () => { + const [isOpen, setIsOpen] = useState(false); + + const toggleDropdown = () => { + setIsOpen(!isOpen); + }; + + return ( +
+
+
+ +
+ + {isOpen && ( +
+
+ + +
+
+ )} +
+
+ ); +}; diff --git a/components/01-atoms/icons/CheckIcon.tsx b/components/01-atoms/icons/CheckIcon.tsx deleted file mode 100644 index 475770cd..00000000 --- a/components/01-atoms/icons/CheckIcon.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { SVGProps } from "react"; - -export const CheckIcon = (props: SVGProps) => { - return ( - - - - ); -}; diff --git a/components/01-atoms/icons/DoneIcon.tsx b/components/01-atoms/icons/DoneIcon.tsx new file mode 100644 index 00000000..82550e34 --- /dev/null +++ b/components/01-atoms/icons/DoneIcon.tsx @@ -0,0 +1,22 @@ +import { SVGProps } from "react"; + +export const DoneIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/ShareIcon.tsx b/components/01-atoms/icons/ShareIcon.tsx new file mode 100644 index 00000000..2a3dcc73 --- /dev/null +++ b/components/01-atoms/icons/ShareIcon.tsx @@ -0,0 +1,22 @@ +import React, { SVGProps } from "react"; + +export const ShareIcon = (props: SVGProps) => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/icons/ThreeDotsIcon.tsx b/components/01-atoms/icons/ThreeDotsIcon.tsx new file mode 100644 index 00000000..8e4f42de --- /dev/null +++ b/components/01-atoms/icons/ThreeDotsIcon.tsx @@ -0,0 +1,20 @@ +import { SVGProps } from "react"; + +export const ThreeDotsIcon = (props: SVGProps) => { + return ( + + + + ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 4cad38c6..49e71079 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -3,6 +3,7 @@ export * from "./ConnectWallet"; export * from "./EmptyNftsCards"; export * from "./LoadingIndicator"; export * from "./OfferExpiryConfirmSwap"; +export * from "./OfferTag"; export * from "./NftsCardApprovedList"; export * from "./ProgressBar"; export * from "./SearchBar"; @@ -17,11 +18,12 @@ export * from "./SwapOfferDetails"; export * from "./SwappingIcons"; export * from "./Tab"; export * from "./TokenCardProperties"; -export * from "./Tooltip"; +export * from "./TokensOfferSkeleton"; +export * from "./ThreeDotsCardOffersOptions"; export * from "./WalletSidebarTemplate"; export * from "./ENSAvatar"; export * from "./icons/ChatIcon"; -export * from "./icons/CheckIcon"; +export * from "./icons/DoneIcon"; export * from "./icons/DangerIcon"; export * from "./icons/EthereumIcon"; export * from "./icons/ErrorIcon"; @@ -43,4 +45,6 @@ export * from "./icons/SunIcon"; export * from "./icons/CopyIcon"; export * from "./icons/MagnifyingGlassIcon"; export * from "./icons/MoonIcon"; +export * from "./icons/ThreeDotsIcon"; export * from "./icons/NoSwapsIcon"; +export * from "./icons/ShareIcon"; From 58c3d315846e5f12024a8535767dc3124aad7b0e Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 13:18:37 -0300 Subject: [PATCH 118/305] feat: add tooltip in export --- components/01-atoms/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 49e71079..594b7511 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -18,6 +18,7 @@ export * from "./SwapOfferDetails"; export * from "./SwappingIcons"; export * from "./Tab"; export * from "./TokenCardProperties"; +export * from "./Tooltip"; export * from "./TokensOfferSkeleton"; export * from "./ThreeDotsCardOffersOptions"; export * from "./WalletSidebarTemplate"; From 9f8e82898becb52c87e8859a353638f7e1b41fef Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 13:26:36 -0300 Subject: [PATCH 119/305] feat: add swap-offer details component --- components/01-atoms/SwapOfferDetails.tsx | 57 +++++++++++++----------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/components/01-atoms/SwapOfferDetails.tsx b/components/01-atoms/SwapOfferDetails.tsx index 76be3e79..d01d16c9 100644 --- a/components/01-atoms/SwapOfferDetails.tsx +++ b/components/01-atoms/SwapOfferDetails.tsx @@ -1,32 +1,37 @@ -import { CheckIcon, XMarkIcon } from "@/components/01-atoms"; +import { + DoneIcon, + OfferTag, + ThreeDotsCardOffersOptions, +} from "@/components/01-atoms"; import React from "react"; export const SwapOfferDetails = () => ( -
-
    -
  • - pending analysis -
  • -
    -
  • expires on
  • -
    -
  • Created by them
  • -
-
- - +
+
+
    + +
  • +
    + Expires on 16 Oct, 2023 +
  • +
  • +
    + Created by you +
  • +
+
+
+
+ +
+ +
); From 45aed80e1391ac6905a70ac6b96c1d8f9cf33b33 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 13:51:10 -0300 Subject: [PATCH 120/305] feat:adjust some types & add globals.css & adjust text in token-properties --- components/01-atoms/ENSAvatar.tsx | 4 +++- components/01-atoms/TokenCardProperties.tsx | 2 +- components/02-molecules/NftCard.tsx | 12 ++++++---- styles/global.css | 26 ++++++++++++++++----- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/components/01-atoms/ENSAvatar.tsx b/components/01-atoms/ENSAvatar.tsx index aefabe4b..214169c1 100644 --- a/components/01-atoms/ENSAvatar.tsx +++ b/components/01-atoms/ENSAvatar.tsx @@ -12,6 +12,8 @@ enum ENSAvatarSize { MEDIUM = "medium", } +type Size = ENSAvatarSize | "small" | "medium"; + const ENSAvatarClassName = { [ENSAvatarSize.SMALL]: "ens-avatar-small", [ENSAvatarSize.MEDIUM]: "ens-avatar-medium", @@ -19,7 +21,7 @@ const ENSAvatarClassName = { interface ENSAvatarProps { avatarENSAddress: EthereumAddress; - size?: ENSAvatarSize; + size?: Size; } export const ENSAvatar = ({ diff --git a/components/01-atoms/TokenCardProperties.tsx b/components/01-atoms/TokenCardProperties.tsx index 3c9ba79a..f0ab9ce8 100644 --- a/components/01-atoms/TokenCardProperties.tsx +++ b/components/01-atoms/TokenCardProperties.tsx @@ -19,7 +19,7 @@ export const TokenCardProperties = ({ {properties.value} ETH

-   ($){properties.value} +   (${properties.value})

diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index e04247ff..535c5052 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -12,7 +12,7 @@ interface INftCard { ownerAddress: string | null; onClickAction?: NftCardActionType; withSelectionValidation?: boolean; - styleType?: NftCardStyleType; + styleType?: StyleVariant; } /** @@ -31,14 +31,18 @@ export enum NftCardActionType { } export enum NftCardStyleType { - "SMALL", - "NORMAL", - "LARGE", + SMALL = "small", + NORMAL = "normal", + MEDIUM = "medium", + LARGE = "large", } +type StyleVariant = NftCardStyleType | "small" | "normal" | "medium" | "large"; + const NftSizeClassNames = { [NftCardStyleType.SMALL]: "card-nft-small", [NftCardStyleType.NORMAL]: "card-nft-normal", + [NftCardStyleType.MEDIUM]: "card-nft-medium", [NftCardStyleType.LARGE]: "card-nft-large", }; diff --git a/styles/global.css b/styles/global.css index 34f520da..0d0cef4f 100644 --- a/styles/global.css +++ b/styles/global.css @@ -22,6 +22,18 @@ input[type="search"]::-webkit-search-results-decoration { box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.3); } + .shadow-token { + box-shadow: 0px 1px 4px 1px #00000026 inset; + } + + .shadow-tag { + box-shadow: 0px 0px 6px 1px #0000004d; + } + + .shadow-three-dots { + box-shadow: 0px 0px 12px 1px #00000066; + } + .title-h1 { } @@ -101,19 +113,21 @@ input[type="search"]::-webkit-search-results-decoration { .p-small-dark { @apply font-onest font-normal text-[14px] leading-[20px] text-[#F6F6F6]; } - - .p-xsmall { - @apply font-onest font-normal text-[12px] leading-[20px]; + .p-small-dark-variant-grey { + @apply font-onest font-normal text-[14px] leading-[20px] text-[#A3A9A5]; } .card-nft-normal { - @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col; + @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; } .card-nft-small { - @apply shadow-inner mx-auto w-[44px] h-[44px] lg:w-[44px] lg:h-[44px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col; + @apply shadow-inner mx-auto w-[44px] h-[44px] lg:w-[44px] lg:h-[44px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; + } + .card-nft-medium { + @apply shadow-inner mx-auto w-[72px] h-[72px] lg:w-[72px] lg:h-[72px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; } .card-nft-large { - @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col; + @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; } .ens-avatar-small { From 1389b8c149288e24a3450385d0da23ce577d4def Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 13:51:41 -0300 Subject: [PATCH 121/305] feat: add user offer info --- components/02-molecules/UserOfferInfo.tsx | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 components/02-molecules/UserOfferInfo.tsx diff --git a/components/02-molecules/UserOfferInfo.tsx b/components/02-molecules/UserOfferInfo.tsx new file mode 100644 index 00000000..9c3a57c3 --- /dev/null +++ b/components/02-molecules/UserOfferInfo.tsx @@ -0,0 +1,31 @@ +import { ENSAvatar } from "@/components/01-atoms"; +import { useEnsData } from "@/lib/client/hooks/useENSData"; +import { collapseAddress } from "@/lib/client/utils"; +import { EthereumAddress } from "@/lib/shared/types"; + +interface UserOfferInfoProps { + address: EthereumAddress | null; +} + +export const UserOfferInfo = ({ address }: UserOfferInfoProps) => { + const { primaryName } = useEnsData({ + ensAddress: address, + }); + const displayAddress = collapseAddress(address?.toString() ?? "") || ""; + return ( +
+
+
+ {address && } +
+
+ {primaryName ? ( +

{primaryName} gets

+ ) : ( +

{displayAddress} gets

+ )} +
+
+
+ ); +}; From 5ae165cb8dbf6633a8cffb3802296c0aa8f8c1f4 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 14:14:40 -0300 Subject: [PATCH 122/305] feat: add card offers & move swapStation to organism --- components/02-molecules/CardOffers.tsx | 42 +++++++++++++++++++ components/02-molecules/index.tsx | 3 +- .../SwapStation.tsx | 0 components/03-organisms/index.tsx | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 components/02-molecules/CardOffers.tsx rename components/{02-molecules => 03-organisms}/SwapStation.tsx (100%) diff --git a/components/02-molecules/CardOffers.tsx b/components/02-molecules/CardOffers.tsx new file mode 100644 index 00000000..02e2d7e8 --- /dev/null +++ b/components/02-molecules/CardOffers.tsx @@ -0,0 +1,42 @@ +import { NftCard, UserOfferInfo } from "@/components/02-molecules"; +import { SwapContext, TokenCardProperties } from "@/components/01-atoms"; +import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import { EthereumAddress } from "@/lib/shared/types"; +import { useContext } from "react"; + +interface CardOffersProps { + address: EthereumAddress | null; +} + +export const CardOffers = ({ address }: CardOffersProps) => { + const { authenticatedUserAddress } = useAuthenticatedUser(); + const { nftAuthUser } = useContext(SwapContext); + + return ( +
+
+
+ +
+
+ {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization +
+ {nftAuthUser.map((nft, index) => ( + + ))} +
+ )} +
+
+ +
+
+
+ ); +}; diff --git a/components/02-molecules/index.tsx b/components/02-molecules/index.tsx index 1ca67ed3..29701855 100644 --- a/components/02-molecules/index.tsx +++ b/components/02-molecules/index.tsx @@ -1,4 +1,5 @@ export * from "./CardHome"; +export * from "./CardOffers"; export * from "./ConfirmSwapModal"; export * from "./EnsNameAndAddressWallet"; export * from "./FilterOffers"; @@ -7,8 +8,8 @@ export * from "./NftsList"; export * from "./OfferSummary"; export * from "./SwapOffersLayout"; export * from "./ProgressStatus"; -export * from "./SwapStation"; export * from "./TheHeader"; export * from "./TheSidebarHeader"; export * from "./UserInfo"; export * from "./AccountBalanceWalletSidebar"; +export * from "./UserOfferInfo"; diff --git a/components/02-molecules/SwapStation.tsx b/components/03-organisms/SwapStation.tsx similarity index 100% rename from components/02-molecules/SwapStation.tsx rename to components/03-organisms/SwapStation.tsx diff --git a/components/03-organisms/index.tsx b/components/03-organisms/index.tsx index 6ce0cddd..c3ca3fbf 100644 --- a/components/03-organisms/index.tsx +++ b/components/03-organisms/index.tsx @@ -1,2 +1,3 @@ export * from "./NftsShelf"; +export * from "./SwapStation"; export * from "./SwappingShelfs"; From 10c23b6451999885920a78c9c55c378bdf2d5752 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 14:16:26 -0300 Subject: [PATCH 123/305] update: change the SwapOfferDetails to TokenOfferDetails --- .../01-atoms/{SwapOfferDetails.tsx => TokenOfferDetails.tsx} | 2 +- components/01-atoms/TokensOfferSkeleton.tsx | 4 ++-- components/01-atoms/index.ts | 2 +- components/04-templates/SwapSection.tsx | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) rename components/01-atoms/{SwapOfferDetails.tsx => TokenOfferDetails.tsx} (96%) diff --git a/components/01-atoms/SwapOfferDetails.tsx b/components/01-atoms/TokenOfferDetails.tsx similarity index 96% rename from components/01-atoms/SwapOfferDetails.tsx rename to components/01-atoms/TokenOfferDetails.tsx index d01d16c9..ffa4fd95 100644 --- a/components/01-atoms/SwapOfferDetails.tsx +++ b/components/01-atoms/TokenOfferDetails.tsx @@ -5,7 +5,7 @@ import { } from "@/components/01-atoms"; import React from "react"; -export const SwapOfferDetails = () => ( +export const TokenOfferDetails = () => (
    diff --git a/components/01-atoms/TokensOfferSkeleton.tsx b/components/01-atoms/TokensOfferSkeleton.tsx index a79b19b6..ff526c21 100644 --- a/components/01-atoms/TokensOfferSkeleton.tsx +++ b/components/01-atoms/TokensOfferSkeleton.tsx @@ -23,7 +23,7 @@ export const TokensOfferSkeleton = () => { ); }; - const SwapOfferDetailsSkeleton = () => { + const TokenOfferDetailsSkeleton = () => { return (
    @@ -49,7 +49,7 @@ export const TokensOfferSkeleton = () => {
    - +
); }; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 594b7511..9caffaf8 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -14,7 +14,7 @@ export * from "./SwapAddManuallyModalLayout"; export * from "./SwapContext"; export * from "./SwapExpireTime"; export * from "./SwapModalButton"; -export * from "./SwapOfferDetails"; +export * from "./TokenOfferDetails"; export * from "./SwappingIcons"; export * from "./Tab"; export * from "./TokenCardProperties"; diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 127e0a47..51fcc025 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -1,6 +1,5 @@ import { SearchBar } from "@/components/01-atoms"; -import { SwapStation } from "@/components/02-molecules"; -import { SwappingShelfs } from "@/components/03-organisms"; +import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( From 79b4ed072fe883f91965e7bc1c9ed3507c3b26c8 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 14:27:45 -0300 Subject: [PATCH 124/305] feat: add swap icon --- components/01-atoms/icons/SwapIcon.tsx | 36 ++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/components/01-atoms/icons/SwapIcon.tsx b/components/01-atoms/icons/SwapIcon.tsx index 48b27697..918142fa 100644 --- a/components/01-atoms/icons/SwapIcon.tsx +++ b/components/01-atoms/icons/SwapIcon.tsx @@ -3,30 +3,31 @@ import { SVGProps } from "react"; export const SwapIcon = (props: SVGProps) => { return ( - + - + ) => { values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> - + - - - ); From 25f9c15e48a633ef80461ffba33d9a9da3b8a082 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 14:28:11 -0300 Subject: [PATCH 125/305] feat: add TokenOffers --- components/03-organisms/TokenOffers.tsx | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 components/03-organisms/TokenOffers.tsx diff --git a/components/03-organisms/TokenOffers.tsx b/components/03-organisms/TokenOffers.tsx new file mode 100644 index 00000000..29502531 --- /dev/null +++ b/components/03-organisms/TokenOffers.tsx @@ -0,0 +1,29 @@ +import { CardOffers } from "@/components/02-molecules"; +import { TokenOfferDetails, SwapIcon } from "@/components/01-atoms"; +import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import cc from "classcat"; + +export const TokenOffers = () => { + const { authenticatedUserAddress } = useAuthenticatedUser(); + + return ( + <> +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ + ); +}; From f7565615ad9f736cda8ad0773ae852a0f7c56206 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Fri, 23 Feb 2024 14:33:18 -0300 Subject: [PATCH 126/305] feat: add token offers in OfferSection --- components/03-organisms/index.tsx | 1 + components/04-templates/OfferSection.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/03-organisms/index.tsx b/components/03-organisms/index.tsx index c3ca3fbf..faec9671 100644 --- a/components/03-organisms/index.tsx +++ b/components/03-organisms/index.tsx @@ -1,3 +1,4 @@ export * from "./NftsShelf"; export * from "./SwapStation"; export * from "./SwappingShelfs"; +export * from "./TokenOffers"; diff --git a/components/04-templates/OfferSection.tsx b/components/04-templates/OfferSection.tsx index de19f884..d0045815 100644 --- a/components/04-templates/OfferSection.tsx +++ b/components/04-templates/OfferSection.tsx @@ -1,4 +1,5 @@ -import { FilterOffers, SwapOffersLayout } from "@/components/02-molecules"; +import { TokenOffers } from "@/components/03-organisms"; +import { FilterOffers } from "@/components/02-molecules"; export const OfferSection = () => { return ( @@ -6,8 +7,8 @@ export const OfferSection = () => {
-
- +
+
); From 81818c752a952fe22718bc133b3960687c9b6e0f Mon Sep 17 00:00:00 2001 From: = <=> Date: Fri, 23 Feb 2024 17:08:22 -0300 Subject: [PATCH 127/305] feat: Add Token Manually Atom/Button --- components/01-atoms/SwapAddTokenCard.tsx | 71 ++++++++++++++++++++++++ components/01-atoms/icons/PlusIcon.tsx | 21 +++++++ components/01-atoms/index.ts | 1 + components/02-molecules/NftsList.tsx | 7 ++- 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 components/01-atoms/SwapAddTokenCard.tsx create mode 100644 components/01-atoms/icons/PlusIcon.tsx diff --git a/components/01-atoms/SwapAddTokenCard.tsx b/components/01-atoms/SwapAddTokenCard.tsx new file mode 100644 index 00000000..54f4c905 --- /dev/null +++ b/components/01-atoms/SwapAddTokenCard.tsx @@ -0,0 +1,71 @@ +import { PlusIcon } from "./icons/PlusIcon"; +import { SwapAddManuallyModalLayout } from "@/components/01-atoms"; +import { useState } from "react"; + +const Tooltip = ({ message }: { message: string }) => { + return ( +
+
+
+ {message} +
+
+
+
+ ); +}; + +export const AddTokenCard = () => { + const [open, setOpen] = useState(false); + + return ( + <> +
+ +
+ +
+
+ + setOpen(false)} + /> + + ); +}; diff --git a/components/01-atoms/icons/PlusIcon.tsx b/components/01-atoms/icons/PlusIcon.tsx new file mode 100644 index 00000000..2dbefbf2 --- /dev/null +++ b/components/01-atoms/icons/PlusIcon.tsx @@ -0,0 +1,21 @@ +// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAnCAIAAAAHNBZfAAAACXBIWXMAABYlAAAWJQFJUiTwAAABVklEQVRYw+2Xy0rDQBSG/zO5aEFL40YQFxX6AIpPIO6Lm2x0o0jBbYp7l94V4gt4qT6Br+EbiBuh4MqixWrSnHHRYtJKI4Gk1DJndQ5z+c4MP/8wJKXEEENguDHuPD3pApZNjx8JE6ZWIhhJl1MivUj4ja9aJ9eElTfWsr3PNr/85AG/SvmZLU/C6y3bSp+Kp3j/1j+Z5Ueseb5Fy0A2/jgNTQ30T5bNd/+eZSvF02jCyhvl6C2GWSt4SBfW8Vif66Ohl5y2LCiX7u6asAwxF/P+sc/1vkcgGj4/e8FT2KK+JCg/EEYFjWbi9SkMMR/fcpRnitJvBSp/UTzFGw8ewewt9Wx5upiNeiPRZLb/h2H/V5Q+R4pXJYLTzYvFDdexgcJm2XVsYHUFFewAC93xaQC8BxAAxwYWL9Zdxw4b3t7CbqWK/YPDo+OT07Pz/vmXV9c3tdu7b/k+dytDxio9AAAAAElFTkSuQmCC + +export const PlusIcon = () => { + return ( + + + + + + ); +}; diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index e02e43d2..96db9546 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -9,6 +9,7 @@ export * from "./SearchBar"; export * from "./SelectAuthedUserChain"; export * from "./SelectDestinyChain"; export * from "./StatusOffers"; +export * from "./SwapAddTokenCard"; export * from "./SwapAddManuallyModalLayout"; export * from "./SwapContext"; export * from "./SwapExpireTime"; diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index 58b56174..324b3412 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -1,6 +1,6 @@ import { NFT } from "@/lib/client/constants"; import { NftCard } from "@/components/02-molecules"; -import { EmptyNftsCards } from "@/components/01-atoms"; +import { EmptyNftsCards, AddTokenCard } from "@/components/01-atoms"; /* eslint-disable react/jsx-key */ interface INftsList { @@ -18,14 +18,15 @@ interface INftsList { */ export const NftsList = ({ nftsList, ownerAddress }: INftsList) => { - const emptySquares = EmptyNftsCards(nftsList.length, 15, 30, 30, 30); + const emptySquares = EmptyNftsCards(nftsList.length+1, 15, 30, 30, 30); + const addTokenSquare = AddTokenCard(); const nftSquares = nftsList.map((nft: NFT, index) => (
)); - const allSquares = [...nftSquares, ...emptySquares]; + const allSquares = [...nftSquares, addTokenSquare, ...emptySquares]; return (
From 981ae1f3f49c05dc3f62de1a9546143aa525e4cd Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Fri, 23 Feb 2024 17:27:10 -0300 Subject: [PATCH 128/305] feat: Integrating ERC20 into dApp's logic --- ...pprovedList.tsx => ApprovedTokenCards.tsx} | 12 +- components/01-atoms/SwapContext.tsx | 10 +- ...ftsCards.tsx => TokenCardsPlaceholder.tsx} | 2 +- components/01-atoms/index.ts | 4 +- .../AccountBalanceWalletSidebar.tsx | 19 ++- components/02-molecules/CardOffers.tsx | 12 +- components/02-molecules/ConfirmSwapModal.tsx | 12 +- components/02-molecules/OfferSummary.tsx | 16 ++- .../{NftCard.tsx => TokenCard.tsx} | 118 ++++++++++-------- components/02-molecules/TokensList.tsx | 14 +-- components/02-molecules/index.ts | 2 +- components/03-organisms/SwapStation.tsx | 2 +- components/03-organisms/SwappingShelfs.tsx | 8 +- .../{NftsShelf.tsx => TokensShelf.tsx} | 117 ++++++++--------- components/03-organisms/index.tsx | 2 +- lib/client/blockchain-data.ts | 77 ++++++++---- lib/client/constants.ts | 2 +- lib/client/swap-utils.ts | 8 +- lib/client/tokens.ts | 6 +- styles/global.css | 2 +- 20 files changed, 254 insertions(+), 191 deletions(-) rename components/01-atoms/{NftsCardApprovedList.tsx => ApprovedTokenCards.tsx} (95%) rename components/01-atoms/{EmptyNftsCards.tsx => TokenCardsPlaceholder.tsx} (95%) rename components/02-molecules/{NftCard.tsx => TokenCard.tsx} (64%) rename components/03-organisms/{NftsShelf.tsx => TokensShelf.tsx} (54%) diff --git a/components/01-atoms/NftsCardApprovedList.tsx b/components/01-atoms/ApprovedTokenCards.tsx similarity index 95% rename from components/01-atoms/NftsCardApprovedList.tsx rename to components/01-atoms/ApprovedTokenCards.tsx index f45ce324..662016e1 100644 --- a/components/01-atoms/NftsCardApprovedList.tsx +++ b/components/01-atoms/ApprovedTokenCards.tsx @@ -5,12 +5,12 @@ import { } from "@/lib/client/constants"; import { SwapContext } from "@/components/01-atoms"; import { - NftCard, + TokenCard, NftCardActionType, NftCardStyleType, } from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { updateNftsToSwapApprovalStatus } from "@/lib/client/swap-utils"; +import { approveTokensBeforeSwap } from "@/lib/client/swap-utils"; import { IApproveSwap } from "@/lib/client/blockchain-data"; import { approveSwap } from "@/lib/service/approveSwap"; import { getTokenName } from "@/lib/client/tokens"; @@ -20,7 +20,7 @@ import { useContext, useEffect } from "react"; import toast from "react-hot-toast"; import { useNetwork, useWalletClient } from "wagmi"; -export const NftsCardApprovedList = () => { +export const ApprovedTokenCards = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); const { chain } = useNetwork(); const { data: walletClient } = useWalletClient(); @@ -35,7 +35,7 @@ export const NftsCardApprovedList = () => { useEffect(() => { const fetchApprove = async () => { - await updateNftsToSwapApprovalStatus( + await approveTokensBeforeSwap( authenticatedUserTokensList, setAuthedUserNftsApprovalStatus, setAllSelectedNftsAreApproved, @@ -122,11 +122,11 @@ export const NftsCardApprovedList = () => { onClick={() => approveNftForSwapping(token, index)} >
-
diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index adb6d902..d3f51b53 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -62,7 +62,7 @@ export const SwapContext = React.createContext({ allSelectedNftsApproved: false, setAuthedUserNftsApprovalStatus: () => {}, authedUserSelectedNftsApprovalStatus: [], - currentSwapModalStep: SwapModalSteps.APPROVE_NFTS, + currentSwapModalStep: SwapModalSteps.APPROVE_TOKENS, updateSwapStep: (buttonClickAction: ButtonClickPossibilities) => {}, }); @@ -81,7 +81,7 @@ export const SwapContextProvider = ({ children }: any) => { const [timeDate, setTimeDate] = useState(BigInt(1)); const [currentSwapModalStep, setCurrentSwapModalStep] = - useState(SwapModalSteps.APPROVE_NFTS); + useState(SwapModalSteps.APPROVE_TOKENS); const [allSelectedNftsApproved, setAllSelectedNftsAreApproved] = useState(false); const [ @@ -140,14 +140,14 @@ export const SwapContextProvider = ({ children }: any) => { const updateSwapStep = (buttonClicked: ButtonClickPossibilities) => { switch (currentSwapModalStep) { - case SwapModalSteps.APPROVE_NFTS: + case SwapModalSteps.APPROVE_TOKENS: if (buttonClicked === ButtonClickPossibilities.NEXT_STEP) { setCurrentSwapModalStep(SwapModalSteps.CREATE_SWAP); } break; case SwapModalSteps.CREATE_SWAP: if (buttonClicked === ButtonClickPossibilities.PREVIOUS_STEP) { - setCurrentSwapModalStep(SwapModalSteps.APPROVE_NFTS); + setCurrentSwapModalStep(SwapModalSteps.APPROVE_TOKENS); } else if (buttonClicked === ButtonClickPossibilities.NEXT_STEP) { setCurrentSwapModalStep(SwapModalSteps.CREATING_SWAP); } @@ -161,7 +161,7 @@ export const SwapContextProvider = ({ children }: any) => { break; case SwapModalSteps.CREATED_SWAP: if (buttonClicked === ButtonClickPossibilities.PREVIOUS_STEP) { - setCurrentSwapModalStep(SwapModalSteps.APPROVE_NFTS); + setCurrentSwapModalStep(SwapModalSteps.APPROVE_TOKENS); } break; } diff --git a/components/01-atoms/EmptyNftsCards.tsx b/components/01-atoms/TokenCardsPlaceholder.tsx similarity index 95% rename from components/01-atoms/EmptyNftsCards.tsx rename to components/01-atoms/TokenCardsPlaceholder.tsx index 1398267c..79d45619 100644 --- a/components/01-atoms/EmptyNftsCards.tsx +++ b/components/01-atoms/TokenCardsPlaceholder.tsx @@ -1,6 +1,6 @@ import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; -export const EmptyNftsCards = ( +export const TokenCardsPlaceholder = ( len: number, ismobileTotalSquares: number, isWideScreenTotalSquares: number, diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 7ed4037a..0cc6e69b 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -1,10 +1,10 @@ export * from "./SwapModalLayout"; export * from "./ConnectWallet"; -export * from "./EmptyNftsCards"; +export * from "./TokenCardsPlaceholder"; export * from "./LoadingIndicator"; export * from "./OfferExpiryConfirmSwap"; export * from "./OfferTag"; -export * from "./NftsCardApprovedList"; +export * from "./ApprovedTokenCards"; export * from "./ProgressBar"; export * from "./SelectAuthedUserChain"; export * from "./StatusOffers"; diff --git a/components/02-molecules/AccountBalanceWalletSidebar.tsx b/components/02-molecules/AccountBalanceWalletSidebar.tsx index d986ad03..d03ac7da 100644 --- a/components/02-molecules/AccountBalanceWalletSidebar.tsx +++ b/components/02-molecules/AccountBalanceWalletSidebar.tsx @@ -22,12 +22,19 @@ export const AccountBalanceWalletSidebar = () => { const displayBalance = match ? match[0] : balance; return ( -
-

Current balance

-
-

{displayBalance}

-

{chain?.nativeCurrency.symbol}

-
+
+

+ Current balance +

+
+

{displayBalance || "0"}

+

{chain?.nativeCurrency.symbol}

+
); }; diff --git a/components/02-molecules/CardOffers.tsx b/components/02-molecules/CardOffers.tsx index 02e2d7e8..9ff35296 100644 --- a/components/02-molecules/CardOffers.tsx +++ b/components/02-molecules/CardOffers.tsx @@ -1,4 +1,4 @@ -import { NftCard, UserOfferInfo } from "@/components/02-molecules"; +import { TokenCard, UserOfferInfo } from "@/components/02-molecules"; import { SwapContext, TokenCardProperties } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { EthereumAddress } from "@/lib/shared/types"; @@ -10,7 +10,7 @@ interface CardOffersProps { export const CardOffers = ({ address }: CardOffersProps) => { const { authenticatedUserAddress } = useAuthenticatedUser(); - const { nftAuthUser } = useContext(SwapContext); + const { authenticatedUserTokensList } = useContext(SwapContext); return (
@@ -19,14 +19,14 @@ export const CardOffers = ({ address }: CardOffersProps) => {
- {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization + {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization
- {nftAuthUser.map((nft, index) => ( - ( + ))} diff --git a/components/02-molecules/ConfirmSwapModal.tsx b/components/02-molecules/ConfirmSwapModal.tsx index af552000..25e8f62e 100644 --- a/components/02-molecules/ConfirmSwapModal.tsx +++ b/components/02-molecules/ConfirmSwapModal.tsx @@ -3,7 +3,7 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { SwapModalLayout, SwapContext, - NftsCardApprovedList, + ApprovedTokenCards, SwapModalButton, ButtonVariant, OfferExpiryConfirmSwap, @@ -19,7 +19,7 @@ import { import { Asset, makeSwap, - updateNftsToSwapApprovalStatus, + approveTokensBeforeSwap, } from "@/lib/client/swap-utils"; import { SwaplaceAbi } from "@/lib/client/abi"; import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants"; @@ -93,7 +93,7 @@ export const ConfirmSwapModal = ({ updateSwapStep(ButtonClickPossibilities.PREVIOUS_STEP); const fetchApprove = async () => { - await updateNftsToSwapApprovalStatus( + await approveTokensBeforeSwap( authenticatedUserTokensList, setAuthedUserNftsApprovalStatus, setAllSelectedNftsAreApproved, @@ -180,7 +180,7 @@ export const ConfirmSwapModal = ({ const validateTokensAreApproved = () => { if (allSelectedNftsApproved) { - if (currentSwapModalStep === SwapModalSteps.APPROVE_NFTS) { + if (currentSwapModalStep === SwapModalSteps.APPROVE_TOKENS) { updateSwapStep(ButtonClickPossibilities.NEXT_STEP); } } else { @@ -189,7 +189,7 @@ export const ConfirmSwapModal = ({ }; const ConfirmSwapModalStep: Partial> = { - [SwapModalSteps.APPROVE_NFTS]: ( + [SwapModalSteps.APPROVE_TOKENS]: ( , + component: , }} footer={{ component: ( diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 8e6ab369..01f60a86 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -1,7 +1,11 @@ -import { NftCard } from "."; +import { TokenCard } from "."; import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { PersonIcon, EmptyNftsCards, SwapContext } from "@/components/01-atoms"; +import { + PersonIcon, + TokenCardsPlaceholder, + SwapContext, +} from "@/components/01-atoms"; import { useEnsName } from "wagmi"; import { useContext } from "react"; @@ -20,14 +24,14 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { }); const { authenticatedUserAddress } = useAuthenticatedUser(); - const emptySquaresAuthUser = EmptyNftsCards( + const emptySquaresAuthUser = TokenCardsPlaceholder( authenticatedUserTokensList.length, 4, 8, 12, 12, ); - const emptySquaresInputUser = EmptyNftsCards( + const emptySquaresInputUser = TokenCardsPlaceholder( searchedUserTokensList.length, 4, 8, @@ -76,7 +80,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { (!forAuthedUser && !validatedAddressToSwap) ? null : ( <> {nftUser.map((nft, index) => ( - { : null : validatedAddressToSwap } - nftData={nft} + tokenData={nft} /> ))} diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/TokenCard.tsx similarity index 64% rename from components/02-molecules/NftCard.tsx rename to components/02-molecules/TokenCard.tsx index 9e816a1b..005a282c 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/TokenCard.tsx @@ -1,12 +1,20 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import { getTokenName } from "@/lib/client/tokens"; import { SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { EthereumAddress, ERC721 } from "@/lib/shared/types"; +import { + ERC20, + ERC721, + EthereumAddress, + Token, + TokenType, +} from "@/lib/shared/types"; import React, { useContext, useEffect, useState } from "react"; import cc from "classcat"; import toast from "react-hot-toast"; -interface INftCard { - nftData: ERC721; +interface TokenCardProps { + tokenData: Token; ownerAddress: string | null; onClickAction?: NftCardActionType; withSelectionValidation?: boolean; @@ -16,10 +24,10 @@ interface INftCard { /** * * This component receives the data of an nft and create a card NFT - * @param nftData + * @param tokenData * @param ownerAddress * - * @returns NftCard + * @returns TokenCard */ export enum NftCardActionType { @@ -44,13 +52,13 @@ const NftSizeClassNames = { [NftCardStyleType.LARGE]: "card-nft-large", }; -export const NftCard = ({ - nftData, +export const TokenCard = ({ + tokenData, ownerAddress, withSelectionValidation = true, styleType = NftCardStyleType.NORMAL, onClickAction = NftCardActionType.SELECT_NFT_FOR_SWAP, -}: INftCard) => { +}: TokenCardProps) => { const { authenticatedUserAddress } = useAuthenticatedUser(); const { setAuthenticatedUsedTokensList, @@ -61,6 +69,35 @@ export const NftCard = ({ const [currentNftIsSelected, setCurrentNftIsSelected] = useState(false); const [couldntLoadNftImage, setCouldntLoadNftImage] = useState(false); + const [tokenDisplayableData, setDisplayableData] = useState({ + id: "", + image: "", + }); + + useEffect(() => { + const displayableData = { ...tokenDisplayableData }; + + switch (tokenData.tokenType) { + case TokenType.ERC20: + if ((tokenData as ERC20).symbol) { + displayableData.image = (tokenData as ERC20).symbol as string; + } + if ((tokenData as ERC20).id) { + displayableData.id = (tokenData as ERC20).id as string; + } + case TokenType.ERC721: + if ((tokenData as ERC721).metadata?.image) { + displayableData.image = (tokenData as ERC721).metadata + ?.image as string; + } + if ((tokenData as ERC721).id) { + displayableData.id = (tokenData as ERC721).id as string; + } + } + + setDisplayableData(displayableData); + }, [tokenData]); + useEffect(() => { const currentNftIsFromAuthedUser = ownerAddress ? authenticatedUserAddress?.equals(new EthereumAddress(ownerAddress)) @@ -69,74 +106,73 @@ export const NftCard = ({ if (currentNftIsFromAuthedUser) { setCurrentNftIsSelected( authenticatedUserTokensList.some( - (selectedNft) => selectedNft.id === nftData.id, + (selectedNft) => selectedNft.id === tokenData.id, ), ); } else { setCurrentNftIsSelected( searchedUserTokensList.some( - (selectedNft) => selectedNft.id === nftData.id, + (selectedNft) => selectedNft.id === tokenData.id, ), ); } }, [ authenticatedUserAddress, - ownerAddress, authenticatedUserTokensList, searchedUserTokensList, - nftData, + ownerAddress, + tokenData, ]); useEffect(() => { setCouldntLoadNftImage(false); - }, [nftData]); - - if (!nftData || !nftData.id || !nftData.contract || !ownerAddress) - return null; + }, [tokenData]); const setNftAsActiveOne = () => { - if (onClickAction === NftCardActionType.SELECT_NFT_FOR_SWAP) { + if ( + onClickAction === NftCardActionType.SELECT_NFT_FOR_SWAP && + ownerAddress + ) { const ownerEthAddress = new EthereumAddress(ownerAddress); if (authenticatedUserAddress?.equals(ownerEthAddress)) { const isSelected = authenticatedUserTokensList.some( - (selectedNft) => selectedNft.id === nftData.id, + (selectedNft) => selectedNft.id === tokenData.id, ); if (isSelected) { setAuthenticatedUsedTokensList((prevNftAuthUser) => prevNftAuthUser.filter( - (selectedNft) => selectedNft.id !== nftData.id, + (selectedNft) => selectedNft.id !== tokenData.id, ), ); } else { setAuthenticatedUsedTokensList((prevNftAuthUser) => [ ...prevNftAuthUser, - nftData, + tokenData, ]); } } else { const isSelected = searchedUserTokensList.some( - (selectedNft) => selectedNft.id === nftData.id, + (selectedNft) => selectedNft.id === tokenData.id, ); if (isSelected) { setSearchedUserTokensList((prevNftInputUser) => prevNftInputUser.filter( - (selectedNft) => selectedNft.id !== nftData.id, + (selectedNft) => selectedNft.id !== tokenData.id, ), ); } else { setSearchedUserTokensList((prevNftInputUser) => [ ...prevNftInputUser, - nftData, + tokenData, ]); } } } else if (onClickAction === NftCardActionType.SHOW_NFT_DETAILS) { - navigator.clipboard.writeText(JSON.stringify(nftData)); + navigator.clipboard.writeText(JSON.stringify(tokenData)); toast.success("NFT data copied to your clipboard"); - } else if (onClickAction === NftCardActionType.NFT_ONCLICK) { } }; @@ -163,40 +199,24 @@ export const NftCard = ({ ); }; - return nftData.metadata?.image && !couldntLoadNftImage ? ( + return tokenDisplayableData.image && !couldntLoadNftImage ? ( <> {ButtonLayout( {nftData.metadata?.name}, )} - ) : nftData.metadata?.name ? ( - <> - {ButtonLayout( -
- {nftData.metadata?.name} -
, - )} - - ) : nftData.name && nftData.id ? ( - <> - {ButtonLayout( -
- {nftData.name} -
, - )} - - ) : nftData.contractMetadata?.name && nftData.id ? ( + ) : ( <> {ButtonLayout( -
- {nftData.contractMetadata?.name} +
+ {getTokenName(tokenData)}
, )} - ) : null; + ); }; diff --git a/components/02-molecules/TokensList.tsx b/components/02-molecules/TokensList.tsx index c2a13f0a..26b5dca8 100644 --- a/components/02-molecules/TokensList.tsx +++ b/components/02-molecules/TokensList.tsx @@ -1,5 +1,5 @@ -import { NftCard } from "@/components/02-molecules"; -import { EmptyNftsCards } from "@/components/01-atoms"; +import { TokenCard } from "@/components/02-molecules"; +import { TokenCardsPlaceholder } from "@/components/01-atoms"; import { Token } from "@/lib/shared/types"; export interface TokensListProps { @@ -9,7 +9,7 @@ export interface TokensListProps { /** * - * This component receives the data of multiple nfts and create its cards + * This component receives the data of multiple tokens and create its cards * @param tokensList * @param ownerAddress * @@ -17,14 +17,14 @@ export interface TokensListProps { */ export const TokensList = ({ tokensList, ownerAddress }: TokensListProps) => { - const emptySquares = EmptyNftsCards(tokensList.length, 15, 30, 30, 30); - const nftSquares = tokensList.map((nft: Token, index) => ( + const placeholders = TokenCardsPlaceholder(tokensList.length, 15, 30, 30, 30); + const tokenCards = tokensList.map((token: Token, index) => (
- +
)); - const allSquares = [...nftSquares, ...emptySquares]; + const allSquares = [...tokenCards, ...placeholders]; return (
diff --git a/components/02-molecules/index.ts b/components/02-molecules/index.ts index a3d360a8..d21d901b 100644 --- a/components/02-molecules/index.ts +++ b/components/02-molecules/index.ts @@ -1,7 +1,7 @@ export * from "./CardHome"; export * from "./CardOffers"; export * from "./ConfirmSwapModal"; -export * from "./NftCard"; +export * from "./TokenCard"; export * from "./EnsNameAndAddressWallet"; export * from "./FilterOffers"; export * from "./TokensList"; diff --git a/components/03-organisms/SwapStation.tsx b/components/03-organisms/SwapStation.tsx index 3c8e0e25..84c64c6e 100644 --- a/components/03-organisms/SwapStation.tsx +++ b/components/03-organisms/SwapStation.tsx @@ -31,7 +31,7 @@ export const SwapStation = () => { const validateSwapSending = () => { if (!isValidSwap) { if (!validatedAddressToSwap) { - toast.error("You must select a destiny wallet to swap NFTs with"); + toast.error("You must select a destiny wallet to swap tokens with"); return; } diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 3559b2d5..715b108e 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { NftsShelf } from "@/components/03-organisms"; +import { TokensShelf } from "@/components/03-organisms"; import { SwapContext, SwappingShelfID, Tab } from "@/components/01-atoms/"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useContext, useEffect, useState } from "react"; @@ -9,7 +9,7 @@ import cc from "classcat"; /** * SwappingShelfs Component * - * React component that display of nfts swapping shelves. + * React component that display of tokens swapping shelves. * * @return The rendered SwappingShelfs component. */ @@ -38,10 +38,10 @@ export const SwappingShelfs = () => { setActiveSwappingShelfID={(input) => setActiveSwappingShelfID(input)} />
- +
- +
); diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/TokensShelf.tsx similarity index 54% rename from components/03-organisms/NftsShelf.tsx rename to components/03-organisms/TokensShelf.tsx index 6d796c9b..0cf3bacd 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/TokensShelf.tsx @@ -1,10 +1,10 @@ -import { ChainInfo, NFTsQueryStatus } from "@/lib/client/constants"; +import { ChainInfo, TokensQueryStatus } from "@/lib/client/constants"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { getERC721TokensFromAddress, getERC20TokensFromAddress, } from "@/lib/client/blockchain-data"; -import { ERC20, EthereumAddress, Token } from "@/lib/shared/types"; +import { EthereumAddress, Token } from "@/lib/shared/types"; import { TokensList } from "@/components/02-molecules"; import { SelectUserIcon, SwapContext } from "@/components/01-atoms"; import { useContext, useEffect, useState } from "react"; @@ -18,17 +18,16 @@ interface TokensShelfProps { /** * - * The Shelf component display the NFTs of given address. + * The Shelf component display the tokens of a given address. * @param address * - * @returns Shelf Nfts based in status of given address + * @returns Tokens Shelf based in status of given address */ -export const NftsShelf = ({ address }: TokensShelfProps) => { +export const TokensShelf = ({ address }: TokensShelfProps) => { const { chain } = useNetwork(); - const [nftsList, setNftsList] = useState(); - const [erc20Tokens, setErc20Tokens] = useState([]); - const [nftsQueryStatus, setNftsQueryStatus] = useState( - NFTsQueryStatus.EMPTY_QUERY, + const [tokenList, setTokensList] = useState([]); + const [tokensQueryStatus, setTokensQueryStatus] = useState( + TokensQueryStatus.EMPTY_QUERY, ); const { theme } = useTheme(); @@ -42,75 +41,79 @@ export const NftsShelf = ({ address }: TokensShelfProps) => { ? chain?.id : ChainInfo[destinyChain].id; + let queriedTokens = [...tokenList]; + let tokensCount = tokenList.length; + if (address && chainId) { - setNftsQueryStatus(NFTsQueryStatus.LOADING); + setTokensQueryStatus(TokensQueryStatus.LOADING); Promise.all([ - getERC721TokensFromAddress(address, chainId).then((nftsList) => { - setNftsList(nftsList); - - if (!nftsList.length) { - setNftsQueryStatus(NFTsQueryStatus.NO_RESULTS); - } else { - setNftsQueryStatus(NFTsQueryStatus.WITH_RESULTS); - } + getERC721TokensFromAddress(address, chainId).then((tokens) => { + queriedTokens = [...queriedTokens, ...tokens]; + tokensCount = tokensCount + tokens.length; }), - getERC20TokensFromAddress(address, chainId).then((erc20Tokens) => { - setErc20Tokens(erc20Tokens); + getERC20TokensFromAddress(address, chainId).then((tokens) => { + queriedTokens = [...queriedTokens, ...tokens]; + tokensCount = tokensCount + tokens.length; }), - ]).catch(() => { - setNftsQueryStatus(NFTsQueryStatus.ERROR); - setErc20Tokens([]); - setNftsList([]); - }); + ]) + .catch(() => { + setTokensQueryStatus(TokensQueryStatus.ERROR); + queriedTokens = []; + }) + .finally(() => { + if (tokensCount === 0) { + setTokensQueryStatus(TokensQueryStatus.NO_RESULTS); + } else { + console.log(queriedTokens); + setTokensList(queriedTokens); + setTokensQueryStatus(TokensQueryStatus.WITH_RESULTS); + } + }); } }, [address, chain, destinyChain]); - useEffect(() => { - if ( - authenticatedUserAddress && - address && - authenticatedUserAddress.equals(new EthereumAddress(address)) - ) { - setNftsList([]); - setErc20Tokens([]); - setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); + const conditionallyCleanTokensList = (condition: boolean) => { + if (condition) { + setTokensList([]); + setTokensQueryStatus(TokensQueryStatus.EMPTY_QUERY); } + }; + + useEffect(() => { + conditionallyCleanTokensList( + !!authenticatedUserAddress && + !!address && + authenticatedUserAddress.equals(new EthereumAddress(address)), + ); }, [destinyChain]); useEffect(() => { - if (address !== authenticatedUserAddress?.address) { - setNftsList([]); - setErc20Tokens([]); - setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); - } + conditionallyCleanTokensList(address !== authenticatedUserAddress?.address); }, [chain]); useEffect(() => { - if ( + conditionallyCleanTokensList( address !== authenticatedUserAddress?.address && - validatedAddressToSwap !== authenticatedUserAddress?.address - ) { - setNftsList([]); - setErc20Tokens([]); - setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); - } + validatedAddressToSwap !== authenticatedUserAddress?.address, + ); }, [inputAddress]); useEffect(() => { - if (!validatedAddressToSwap) { - setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); - } + conditionallyCleanTokensList(!validatedAddressToSwap); }, [validatedAddressToSwap]); + useEffect(() => { + conditionallyCleanTokensList(!authenticatedUserAddress); + }, [authenticatedUserAddress]); + return (
- {nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? ( + {tokensQueryStatus == TokensQueryStatus.WITH_RESULTS && tokenList ? (
- - <>{erc20Tokens[0]?.name} +
- ) : nftsQueryStatus == NFTsQueryStatus.EMPTY_QUERY || !address ? ( + ) : tokensQueryStatus == TokensQueryStatus.EMPTY_QUERY || !address ? (
@@ -127,19 +130,19 @@ export const NftsShelf = ({ address }: TokensShelfProps) => {

- ) : nftsQueryStatus == NFTsQueryStatus.NO_RESULTS ? ( + ) : tokensQueryStatus == TokensQueryStatus.NO_RESULTS ? (

- Given address has no NFTs associated in the given network + Given address has no tokens associated in the given network

- ) : nftsQueryStatus == NFTsQueryStatus.LOADING ? ( + ) : tokensQueryStatus == TokensQueryStatus.LOADING ? (

- Loading NFTs of{" "} + Loading tokens of{" "} {new EthereumAddress(address).getEllipsedAddress()}...

diff --git a/components/03-organisms/index.tsx b/components/03-organisms/index.tsx index faec9671..f1fcd106 100644 --- a/components/03-organisms/index.tsx +++ b/components/03-organisms/index.tsx @@ -1,4 +1,4 @@ -export * from "./NftsShelf"; +export * from "./TokensShelf"; export * from "./SwapStation"; export * from "./SwappingShelfs"; export * from "./TokenOffers"; diff --git a/lib/client/blockchain-data.ts b/lib/client/blockchain-data.ts index 2ba9d7c0..905911c0 100644 --- a/lib/client/blockchain-data.ts +++ b/lib/client/blockchain-data.ts @@ -38,7 +38,7 @@ export interface IApproveSwap { } export enum SwapModalSteps { - APPROVE_NFTS, + APPROVE_TOKENS, CREATE_SWAP, CREATING_SWAP, CREATED_SWAP, @@ -56,20 +56,31 @@ export enum TransactionStatus { SUCCESSFUL_TRANSACTION, } -export type NftSwappingInfo = { +export type TokensWithSwapInfo = { tokenAddress: `0x${string}`; amountOrId: bigint; }; export async function ComposeTokenUserAssets( - nftUser: Token[], + tokensList: Token[], ): Promise { const tokenAssetArray: Asset[] = []; const assetPromisesArray: Promise[] = []; - for (let i = 0; i < nftUser.length; i += 1) { - const addr = nftUser[i]?.contract as `0x${string}`; - const amountOrId = BigInt(nftUser[i].id as unknown as number); + for (let i = 0; i < tokensList.length; i += 1) { + const addr = tokensList[i]?.contract as `0x${string}`; + let amountOrId = undefined; + + switch (tokensList[i].tokenType) { + case TokenType.ERC20: + if ((tokensList[i] as ERC20).rawBalance) { + amountOrId = BigInt((tokensList[i] as ERC20).rawBalance as string); + } + case TokenType.ERC721: + if (tokensList[i]?.id as unknown as number) { + amountOrId = tokensList[i]?.id as unknown as number; + } + } if (amountOrId !== undefined && addr !== undefined) { const assetPromise = makeAsset(addr, amountOrId).then((asset) => { @@ -84,31 +95,39 @@ export async function ComposeTokenUserAssets( return tokenAssetArray; } -export function getNftsInfoToSwap(userNfts: Token[]): NftSwappingInfo[] { - const nftsInfoArray: NftSwappingInfo[] = []; +export function getTokensInfoBeforeSwap( + tokensList: Token[], +): TokensWithSwapInfo[] { + const tokensWithInfo: TokensWithSwapInfo[] = []; + + for (let i = 0; i < tokensList.length; i++) { + let nftAmountOrTokenId = undefined; + + switch (tokensList[i].tokenType) { + case TokenType.ERC20: + if ((tokensList[i] as ERC20).rawBalance) { + nftAmountOrTokenId = (tokensList[i] as ERC20).rawBalance; + } + case TokenType.ERC721: + if (tokensList[i]?.id as unknown as number) { + nftAmountOrTokenId = tokensList[i]?.id as unknown as number; + } + } - for (let i = 0; i < userNfts.length; i++) { - const nftAmountOrTokenId = BigInt(userNfts[i]?.id as unknown as number); - const nftContractAddress = userNfts[i]?.contract as `0x${string}`; + const tokenContractAddress = tokensList[i]?.contract as `0x${string}`; - if (nftAmountOrTokenId !== undefined && nftContractAddress !== undefined) { - nftsInfoArray.push({ - tokenAddress: nftContractAddress, - amountOrId: nftAmountOrTokenId, + if ( + nftAmountOrTokenId !== undefined && + tokenContractAddress !== undefined + ) { + tokensWithInfo.push({ + tokenAddress: tokenContractAddress, + amountOrId: BigInt(nftAmountOrTokenId), }); } - - // if (i + 1 < userNfts.length) { - // const nextAmountOrId = BigInt(hexToNumber(userNfts[i + 1]?.id?.tokenId)); - // const nextAddr = userNfts[i + 1]?.contract?.address as `0x${string}`; - - // if (nextAmountOrId !== undefined && nextAddr !== undefined) { - // nftsInfoArray.push([nextAddr, nextAmountOrId]); - // } - // } } - return nftsInfoArray; + return tokensWithInfo; } // Check out the Alchemy Documentation https://docs.alchemy.com/reference/getnfts-sdk-v3 @@ -192,6 +211,14 @@ const parseAlchemyERC20Tokens = (tokens: OwnedToken[]): ERC20[] => { return tokens.map((token) => { return { tokenType: TokenType.ERC20, + /* + This ID is only used for TokenCard selection, in the Ui of the dApp. + We want it to be as randomic and unique as possible besides being + yet, mathematically possible to have same IDs on two different + tokens. Possible, but very unlikely to generate non-unique + IDs, below maths solve our ID generation goal, today. + */ + id: ((Date.now() * Math.random()) / Math.random()).toFixed(0), name: token.name, logo: token.logo, symbol: token.symbol, diff --git a/lib/client/constants.ts b/lib/client/constants.ts index beb28b7d..33a7512e 100644 --- a/lib/client/constants.ts +++ b/lib/client/constants.ts @@ -7,7 +7,7 @@ export const WIDE_SCREEN_SIZE = 1279; export const DESKTOP_SCREEN_SIZE = 1023; export const TABLET_SCREEN_SIZE = 768; -export enum NFTsQueryStatus { +export enum TokensQueryStatus { EMPTY_QUERY = "EMPTY_QUERY", LOADING = "LOADING", ERROR = "ERROR", diff --git a/lib/client/swap-utils.ts b/lib/client/swap-utils.ts index ca5e845e..97d7358b 100644 --- a/lib/client/swap-utils.ts +++ b/lib/client/swap-utils.ts @@ -1,6 +1,6 @@ import { IArrayStatusTokenApproved, - getNftsInfoToSwap, + getTokensInfoBeforeSwap, } from "./blockchain-data"; import { ADDRESS_ZERO } from "./constants"; import { getTimestamp } from "./utils"; @@ -8,12 +8,12 @@ import { EthereumAddress, Token } from "../shared/types"; import { getMultipleNftsApprovalStatus } from "../service/verifyTokensSwapApproval"; import { Dispatch, SetStateAction } from "react"; -export const updateNftsToSwapApprovalStatus = async ( - nftsList: Token[], +export const approveTokensBeforeSwap = async ( + tokensList: Token[], setNftsApprovalStatus: Dispatch>, setNftsAreAllApproved: (areApproved: boolean) => void, ) => { - const nftsToSwapFromAuthedUser = getNftsInfoToSwap(nftsList); + const nftsToSwapFromAuthedUser = getTokensInfoBeforeSwap(tokensList); try { const result = await getMultipleNftsApprovalStatus( nftsToSwapFromAuthedUser, diff --git a/lib/client/tokens.ts b/lib/client/tokens.ts index 8d14bae8..9a64d7b1 100644 --- a/lib/client/tokens.ts +++ b/lib/client/tokens.ts @@ -1,13 +1,15 @@ import { ERC721, Token, TokenType } from "../shared/types"; -export const getTokenName = (token: Token) => { +export const getTokenName = (token: Token): string => { if (token.tokenType === TokenType.ERC20) { return token.name ? token.name : token.tokenType; } else if (token.tokenType === TokenType.ERC721) { return (token as ERC721).metadata ? (token as ERC721).metadata?.name : token.name - ? token.name + ? `${token.name} - ${token.tokenType}` : token.tokenType; + } else { + return `${token.tokenType} - Token Name Not Found`; } }; diff --git a/styles/global.css b/styles/global.css index 0d0cef4f..187fdbf7 100644 --- a/styles/global.css +++ b/styles/global.css @@ -118,7 +118,7 @@ input[type="search"]::-webkit-search-results-decoration { } .card-nft-normal { - @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; + @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token px-1; } .card-nft-small { @apply shadow-inner mx-auto w-[44px] h-[44px] lg:w-[44px] lg:h-[44px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; From 5642cd7625605f6227ab047e4310a5ab6e8c8c43 Mon Sep 17 00:00:00 2001 From: Deepu Date: Sat, 24 Feb 2024 03:19:04 +0530 Subject: [PATCH 129/305] closes #122 --- .env.example | 27 ++++++++- lib/client/constants.ts | 119 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index ba56e297..ddabee2b 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,32 @@ NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=50db9e195634356bb8ab0375a9f07607 +NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= +NEXT_PUBLIC_ALCHEMY_ETHEREUM_KEY= NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= +NEXT_PUBLIC_ALCHEMY_POLYGON_HTTP= +NEXT_PUBLIC_ALCHEMY_POLYGON_KEY= NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY= -NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= +NEXT_PUBLIC_ALCHEMY_OPTIMISM_HTTP= +NEXT_PUBLIC_ALCHEMY_OPTIMISM_KEY= +NEXT_PUBLIC_ALCHEMY_OPGOERLI_HTTP= +NEXT_PUBLIC_ALCHEMY_OPGOERLI_KEY= +NEXT_PUBLIC_ALCHEMY_OPSEPOLIA_HTTP= +NEXT_PUBLIC_ALCHEMY_OPSEPOLIA_KEY= +NEXT_PUBLIC_ALCHEMY_AVALANCHE_HTTP= +NEXT_PUBLIC_ALCHEMY_AVALANCHE_KEY= +NEXT_PUBLIC_ALCHEMY_FUJI_HTTP= +NEXT_PUBLIC_ALCHEMY_FUJI_KEY= +NEXT_PUBLIC_ALCHEMY_BASE_HTTP= +NEXT_PUBLIC_ALCHEMY_BASE_KEY= +NEXT_PUBLIC_ALCHEMY_BASEGOERLI_HTTP= +NEXT_PUBLIC_ALCHEMY_BASEGOERLI_KEY= +NEXT_PUBLIC_ALCHEMY_BNBTESTNET_HTTP= +NEXT_PUBLIC_ALCHEMY_BNBTESTNET_KEY= +NEXT_PUBLIC_ALCHEMY_ARBITRUMONE_HTTP= +NEXT_PUBLIC_ALCHEMY_ARBITRUMONE_KEY= +NEXT_PUBLIC_ALCHEMY_ARBITRUMSEPOLIA_HTTP= +NEXT_PUBLIC_ALCHEMY_ARBITRUMSEPOLIA_KEY= # Subgraph endpoint production query @@ -14,4 +37,4 @@ NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= NEXT_PUBLIC_ENDPOINT_URL=https://api.studio.thegraph.com/query/57887/swaplace-subgraph-sepolia/version/latest -NEXT_PUBLIC_SUBGRAPH_AUTH_KEY=3b2048f02febad918a35bbafe78b2115 +NEXT_PUBLIC_SUBGRAPH_AUTH_KEY=3b2048f02febad918a35bbafe78b2115 \ No newline at end of file diff --git a/lib/client/constants.ts b/lib/client/constants.ts index a90473b0..d1128266 100644 --- a/lib/client/constants.ts +++ b/lib/client/constants.ts @@ -21,9 +21,22 @@ export enum NFTsQueryStatus { } export enum SupportedNetworks { + HARDHAT = "HARDHAT", + ETHEREUM = "ETHEREUM", SEPOLIA = "SEPOLIA", + POLYGON = "POLYGON", MUMBAI = "MUMBAI", - HARDHAT = "HARDHAT", + OPTIMISM = "OPTIMISM", + OPGOERLI = "OPGOERLI", + OPSEPOLIA = "OPSEPOLIA", + AVALANCHE = "AVALANCHE", + FUJI = "FUJI", + BASE = "BASE", + BASEGOERLI = "BASEGOERLI", + BNB = "BNB", + BNBTESTNET = "BNBTESTNET", + ARBITRUMONE = "ARBITRUMONE", + ARBITRUMSEPOLIA = "ARBITRUMSEPOLIA", } interface ChainProps { @@ -32,30 +45,126 @@ interface ChainProps { } export const ChainInfo: Record = { + [SupportedNetworks.HARDHAT]: { + id: 31337, + name: "Hardhat", + }, + [SupportedNetworks.ETHEREUM]: { + id: 1, + name: "Ethereum", + }, [SupportedNetworks.SEPOLIA]: { id: 11155111, name: "Sepolia", }, + [SupportedNetworks.POLYGON]: { + id: 137, + name: "Polygon", + }, [SupportedNetworks.MUMBAI]: { id: 80001, name: "Polygon Mumbai", }, - [SupportedNetworks.HARDHAT]: { - id: 31337, - name: "Hardhat", + [SupportedNetworks.OPTIMISM]: { + id: 10, + name: "Optimism", + }, + [SupportedNetworks.OPGOERLI]: { + id: 420, + name: "Optimism Goerli", + }, + [SupportedNetworks.OPSEPOLIA]: { + id: 11155420, + name: "Optimism Sepolia", + }, + [SupportedNetworks.AVALANCHE]: { + id: 43114, + name: "Avalanche", + }, + [SupportedNetworks.FUJI]: { + id: 43113, + name: "Fuji", + }, + [SupportedNetworks.BASE]: { + id: 8453, + name: "Base", + }, + [SupportedNetworks.BASEGOERLI]: { + id: 84531, + name: "Base Goerli", + }, + [SupportedNetworks.BNB]: { + id: 56, + name: "Bnb", + }, + [SupportedNetworks.BNBTESTNET]: { + id: 97, + name: "Bnb Testnet", + }, + [SupportedNetworks.ARBITRUMONE]: { + id: 42161, + name: "Arbitrum", + }, + [SupportedNetworks.ARBITRUMSEPOLIA]: { + id: 421614, + name: "Arbitrum Sepolia", }, }; export const getRpcHttpUrlForNetwork: Map = new Map([ + [ChainInfo.HARDHAT.id, "http://127.0.0.1:8545/"], + [ChainInfo.ETHEREUM.id, process.env.NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP ?? ""], [ChainInfo.SEPOLIA.id, process.env.NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP ?? ""], + [ChainInfo.POLYGON.id, process.env.NEXT_PUBLIC_ALCHEMY_POLYGON_HTTP ?? ""], [ChainInfo.MUMBAI.id, process.env.NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP ?? ""], - [ChainInfo.HARDHAT.id, "http://127.0.0.1:8545/"], + [ChainInfo.OPTIMISM.id, process.env.NEXT_PUBLIC_ALCHEMY_OPTIMISM_HTTP ?? ""], + [ChainInfo.OPGOERLI.id, process.env.NEXT_PUBLIC_ALCHEMY_OPGOERLI_HTTP ?? ""], + [ + ChainInfo.OPSEPOLIA.id, + process.env.NEXT_PUBLIC_ALCHEMY_OPSEPOLIA_HTTP ?? "", + ], + [ + ChainInfo.AVALANCHE.id, + process.env.NEXT_PUBLIC_ALCHEMY_AVALANCHE_HTTP ?? "", + ], + [ChainInfo.FUJI.id, process.env.NEXT_PUBLIC_ALCHEMY_FUJI_HTTP ?? ""], + [ChainInfo.BASE.id, process.env.NEXT_PUBLIC_ALCHEMY_BASE_HTTP ?? ""], + [ + ChainInfo.BASEGOERLI.id, + process.env.NEXT_PUBLIC_ALCHEMY_BASEGOERLI_HTTP ?? "", + ], + [ChainInfo.BNB.id, process.env.NEXT_PUBLIC_ALCHEMY_BNB_HTTP ?? ""], + [ + ChainInfo.BNBTESTNET.id, + process.env.NEXT_PUBLIC_ALCHEMY_BNBTESTNET_HTTP ?? "", + ], + [ + ChainInfo.ARBITRUMONE.id, + process.env.NEXT_PUBLIC_ALCHEMY_ARBITRUMONE_HTTP ?? "", + ], + [ + ChainInfo.ARBITRUMSEPOLIA.id, + process.env.NEXT_PUBLIC_ALCHEMY_ARBITRUMSEPOLIA_HTTP ?? "", + ], ]); export const SWAPLACE_SMART_CONTRACT_ADDRESS = { [ChainInfo.HARDHAT.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.ETHEREUM.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", [ChainInfo.SEPOLIA.id]: "0xD8E3580C1b6f117c5b35DdD01dd9e50d9487501D", + [ChainInfo.POLYGON.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", [ChainInfo.MUMBAI.id]: "0xcB003ed4Df4679D15b8863BB8F7609855A6a380d", + [ChainInfo.OPTIMISM.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.OPGOERLI.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.OPSEPOLIA.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.AVALANCHE.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.FUJI.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.BASE.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.BASEGOERLI.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.BNB.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.BNBTESTNET.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.ARBITRUMONE.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + [ChainInfo.ARBITRUMSEPOLIA.id]: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", }; //SEPOLIA MOCKS From 153cda2b59f75d05cfbff14e978e121dc664432c Mon Sep 17 00:00:00 2001 From: = <=> Date: Sat, 24 Feb 2024 09:33:26 -0300 Subject: [PATCH 130/305] feat: Add Token Manually Atom/Button --- components/01-atoms/SwapAddTokenCard.tsx | 36 ++-------------------- components/01-atoms/icons/PlusIcon.tsx | 2 -- components/02-molecules/NftsList.tsx | 31 ++++++++++++------- components/03-organisms/NftsShelf.tsx | 5 +-- components/03-organisms/SwappingShelfs.tsx | 4 +-- 5 files changed, 28 insertions(+), 50 deletions(-) diff --git a/components/01-atoms/SwapAddTokenCard.tsx b/components/01-atoms/SwapAddTokenCard.tsx index 54f4c905..4d0ed910 100644 --- a/components/01-atoms/SwapAddTokenCard.tsx +++ b/components/01-atoms/SwapAddTokenCard.tsx @@ -1,37 +1,7 @@ import { PlusIcon } from "./icons/PlusIcon"; -import { SwapAddManuallyModalLayout } from "@/components/01-atoms"; +import { SwapAddManuallyModalLayout, Tooltip } from "@/components/01-atoms"; import { useState } from "react"; - -const Tooltip = ({ message }: { message: string }) => { - return ( -
-
-
- {message} -
-
-
-
- ); -}; - -export const AddTokenCard = () => { +export const SwapAddTokenCard = () => { const [open, setOpen] = useState(false); return ( @@ -50,7 +20,7 @@ export const AddTokenCard = () => { transition-all duration-200 " > - +
) : ( - + 1440 ? "right" : "bottom"} content={"Dark Mode"}> ) : ( - + 1440 ? "right" : "bottom"} content={"Connect a Wallet"}>
{ ) : ( <> {!!authenticatedUserAddress ? ( - + 1440 ? "right" : "bottom"} content={"Your wallet"}> ) : ( - + 1440 ? "right" : "bottom"} content={"Connect a Wallet"}>
{ }; return ( -
+
diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 51fcc025..b5fa79cf 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -1,14 +1,18 @@ import { SearchBar } from "@/components/01-atoms"; +import { TheHeader } from "@/components/02-molecules"; import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( -
-
- - -
- -
+
+
+ +
+
+ + +
+ +
); }; diff --git a/pages/index.tsx b/pages/index.tsx index ed4a9a8e..e39c45f9 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,3 @@ -import { TheHeader } from "@/components/02-molecules"; import { Layout, SwapSection } from "@/components/04-templates"; import cc from "classcat"; @@ -7,10 +6,9 @@ export default function IndexPage() {
-
diff --git a/pages/offers.tsx b/pages/offers.tsx index 221a4915..3757d51f 100644 --- a/pages/offers.tsx +++ b/pages/offers.tsx @@ -12,10 +12,12 @@ export default function Offers() { {authenticatedUserAddress && (
+
+
)} From df0ab0933ad19cebf0b3d991a479cfcc655d2a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Mon, 26 Feb 2024 03:04:59 -0300 Subject: [PATCH 133/305] refactor: add address search function just by typing it --- components/01-atoms/SearchBar.tsx | 105 ++++++++++++++++-------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index a50ab7dc..ce645981 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -3,34 +3,30 @@ /* eslint-disable import/no-named-as-default-member */ import { MagnifyingGlassIcon, SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { useContext, useEffect, useState } from "react"; +import { SearchUserDelay } from "@/lib/client/constants"; +import { useContext, useEffect } from "react"; import { useTheme } from "next-themes"; import { ENS } from "web3-eth-ens"; import cc from "classcat"; import Web3 from "web3"; export const SearchBar = () => { - const { setInputAddress, inputAddress, validateAddressToSwap } = + const { setInputAddress, inputAddress, validateAddressToSwap, setUserJustValidatedInput } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); - const [validateAfterENSaddressLoads, setValidateAfterENSaddressLoads] = - useState(false); - const validateInput = () => { - if (authenticatedUserAddress) { - if (loadingENSaddress) { - setValidateAfterENSaddressLoads(true); - } else { - validateAddressToSwap(authenticatedUserAddress, ensNameAddress); - } - } - }; const { theme } = useTheme(); - const [ensNameAddress, setEnsNameAddress] = useState(""); - const [loadingENSaddress, setLoadingENSaddress] = useState(false); - useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars + + const validateUser = (ensNameAddress: string) => { + if (!authenticatedUserAddress) return + + validateAddressToSwap(authenticatedUserAddress, ensNameAddress); + } + + const getUserAddress = async () => { if (inputAddress) { if (!process.env.NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP) { throw new Error( @@ -44,40 +40,45 @@ export const SearchBar = () => { const ens = new ENS(undefined, provider); - ens - .getOwner( - inputAddress.toLowerCase().includes(".") - ? inputAddress.toLowerCase().includes(".eth") - ? inputAddress.split(".")[1].length >= 3 - ? inputAddress - : `${inputAddress.split(".")[0]}.eth` - : inputAddress.split(".")[1].length >= 3 + const formattedAddress = + inputAddress.toLowerCase().includes(".") + ? inputAddress.toLowerCase().includes(".eth") + ? inputAddress.split(".")[1].length >= 3 ? inputAddress : `${inputAddress.split(".")[0]}.eth` - : `${inputAddress}.eth`, - ) - .then((address: unknown) => { - if (typeof address == "string") { - setEnsNameAddress(address); - setLoadingENSaddress(false); - } else { - setEnsNameAddress(""); - setLoadingENSaddress(false); - } - }) - .catch(() => { - setEnsNameAddress(""); - setLoadingENSaddress(false); - }); + : inputAddress.split(".")[1].length >= 3 + ? inputAddress + : `${inputAddress.split(".")[0]}.eth` + : `${inputAddress}.eth`; + + try { + const address: unknown = await ens.getOwner(formattedAddress); + + if (typeof address !== "string") return + validateUser(address); + + } + catch (e) { + console.log(e); + } + finally { + setUserJustValidatedInput(true); + } } - }, [inputAddress]); + } useEffect(() => { - if (!loadingENSaddress && validateAfterENSaddressLoads) { - validateInput(); - setValidateAfterENSaddressLoads(false); - } - }, [loadingENSaddress]); + const requestDelay = setTimeout(() => { + + setUserJustValidatedInput(false); + + getUserAddress(); + + }, SearchUserDelay); + + return () => clearTimeout(requestDelay); + + }, [inputAddress]); return (
@@ -92,15 +93,14 @@ export const SearchBar = () => { name="search" type="search" className={cc([ - "dark:bg-[#212322] w-full h-11 px-4 py-3 border-2 border-gray-100 dark:border-[#353836] focus:ring-0 focus:ring-transparent focus:outline-none focus-visible:border-gray-300 rounded-xl placeholder:p-small dark:placeholder:p-small ", + "dark:bg-[#212322] w-full h-11 px-4 py-3 border-2 border-gray-100 dark:border-[#353836] focus:ring-0 focus:ring-transparent focus:outline-none focus-visible:border-gray-300 rounded-xl placeholder:p-small dark:placeholder:p-small ", ])} placeholder="Search username, address or ENS" - onChange={(e) => setInputAddress(e.target.value)} + onChange={({ target }) => setInputAddress(target.value)} />
@@ -127,3 +127,8 @@ export const SearchBar = () => {
); }; + + + +//primeira busca após conectar wallet: Se for um ENS, irá (as vezes) não aparecer o inventário. +//problema: TheirItems não mostra o inventário da mesma busca duas vezes consecutivas. From 8ee93642ba23d7143d455dcaebf6a861f50d20a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Mon, 26 Feb 2024 03:05:30 -0300 Subject: [PATCH 134/305] refactor: add address search function just by typing it --- components/01-atoms/SearchBar.tsx | 52 ++++++++++--------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index ce645981..ffdef78a 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -3,7 +3,6 @@ /* eslint-disable import/no-named-as-default-member */ import { MagnifyingGlassIcon, SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { SearchUserDelay } from "@/lib/client/constants"; import { useContext, useEffect } from "react"; import { useTheme } from "next-themes"; import { ENS } from "web3-eth-ens"; @@ -20,7 +19,7 @@ export const SearchBar = () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars - const validateUser = (ensNameAddress: string) => { + const validateUser = (ensNameAddress: string | null) => { if (!authenticatedUserAddress) return validateAddressToSwap(authenticatedUserAddress, ensNameAddress); @@ -68,14 +67,14 @@ export const SearchBar = () => { } useEffect(() => { + const requestDelay = setTimeout(() => { setUserJustValidatedInput(false); getUserAddress(); - }, SearchUserDelay); - + }, 2000); return () => clearTimeout(requestDelay); }, [inputAddress]); @@ -87,48 +86,29 @@ export const SearchBar = () => { Who are you swapping with today?
-
+
+
+ +
setInputAddress(target.value)} /> -
-
- -
-
); }; - - - -//primeira busca após conectar wallet: Se for um ENS, irá (as vezes) não aparecer o inventário. -//problema: TheirItems não mostra o inventário da mesma busca duas vezes consecutivas. From d38de0d6872343063a8bdbd8c034d7c9c731fc5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Mon, 26 Feb 2024 03:17:02 -0300 Subject: [PATCH 135/305] fixed: when searching the seame address twice, now the error message not display and inventory items display. --- components/02-molecules/OfferSummary.tsx | 33 +++++++++---------- components/03-organisms/NftsShelf.tsx | 41 ++++++++++++++++-------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index bccf2d02..c0f9b7d3 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -2,7 +2,6 @@ import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { NftCard } from "@/components/02-molecules"; import { EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; -import { useEnsName } from "wagmi"; import { useContext } from "react"; interface IOfferSummary { @@ -10,11 +9,8 @@ interface IOfferSummary { } export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { - const { validatedAddressToSwap, nftAuthUser, nftInputUser } = + const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress, userJustValidatedInput } = useContext(SwapContext); - const { data } = useEnsName({ - address: validatedAddressToSwap as `0x${string}`, - }); const { authenticatedUserAddress } = useAuthenticatedUser(); const emptySquaresAuthUser = EmptyNftsCards(nftAuthUser.length, 4, 8, 12, 12); @@ -25,9 +21,11 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { 12, 12, ); - + const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; + + return (
@@ -37,17 +35,16 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {

- {forAuthedUser - ? "You give" - : !forAuthedUser && !validatedAddressToSwap - ? "Use the search bar!" - : `${ - data - ? data - : new EthereumAddress( - validatedAddressToSwap, - ).getEllipsedAddress() - } gives`} + { + forAuthedUser + ? "You give" + : !forAuthedUser && validatedAddressToSwap && inputAddress + ? `${userJustValidatedInput ? + new EthereumAddress(validatedAddressToSwap).getEllipsedAddress() + " gives" + : "Use the search bar!" + }` + : "Use the search bar!" + }

@@ -62,7 +59,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {
{(forAuthedUser && !authenticatedUserAddress?.address) || - (!forAuthedUser && !validatedAddressToSwap) ? null : ( + (!forAuthedUser && !validatedAddressToSwap) ? null : ( <> {nftUser.map((nft, index) => ( { const { theme } = useTheme(); const { authenticatedUserAddress } = useAuthenticatedUser(); - const { validatedAddressToSwap, inputAddress, destinyChain } = + const { validatedAddressToSwap, inputAddress, destinyChain, userJustValidatedInput } = useContext(SwapContext); - useEffect(() => { + const [addressSearchCount, setAddressSearchCount] = useState(0) + + const showUserItems = async () => { const chainId = address === authenticatedUserAddress?.address ? chain?.id : ChainInfo[destinyChain].id; + if(addressSearchCount > 1) return //When a new address is added, all useEffect parameters are updated + // addressSearchCount prevents multiple API calls from occurring, causing undesired behavior to occur. + if (address && chainId && inputAddress) { + try { + const nftsList = await getNftsFrom(address, chainId, setNftsQueryStatus) + + setNftsList(nftsList); + + } catch (_) { - if (address && chainId) { - getNftsFrom(address, chainId, setNftsQueryStatus) - .then((nftsList) => { - setNftsList(nftsList); - }) - .catch(() => { - setNftsList([]); - }); + setNftsList([]); + } + + setAddressSearchCount((prev)=> prev + 1) } - }, [address, chain, destinyChain]); + + } + + useEffect(() => { + showUserItems() + console.log(userJustValidatedInput) + }, [address, chain, destinyChain, userJustValidatedInput]); useEffect(() => { if ( @@ -70,16 +83,18 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { useEffect(() => { if ( address !== authenticatedUserAddress?.address && - validatedAddressToSwap !== authenticatedUserAddress?.address + validatedAddressToSwap !== authenticatedUserAddress?.address || !inputAddress ) { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } + setAddressSearchCount(0) }, [inputAddress]); useEffect(() => { if (!validatedAddressToSwap) { setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); + console.log("entrou aqui") } }, [validatedAddressToSwap]); From 847b51da0938a6798129f32230c5d61a984b69b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Mon, 26 Feb 2024 03:48:33 -0300 Subject: [PATCH 136/305] remove logs --- components/03-organisms/NftsShelf.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 1a97b49e..6cc989da 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -94,7 +94,6 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { useEffect(() => { if (!validatedAddressToSwap) { setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); - console.log("entrou aqui") } }, [validatedAddressToSwap]); From 788a5b54c294b43abd23e967d1619d58a8b10542 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 12:25:45 -0300 Subject: [PATCH 137/305] update: improvements in EmptyNftsCards to fill all the items --- components/01-atoms/EmptyNftsCards.tsx | 23 +++++++++++++++++------ components/02-molecules/NftsList.tsx | 7 ++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/components/01-atoms/EmptyNftsCards.tsx b/components/01-atoms/EmptyNftsCards.tsx index 1398267c..cb67f5ef 100644 --- a/components/01-atoms/EmptyNftsCards.tsx +++ b/components/01-atoms/EmptyNftsCards.tsx @@ -1,7 +1,7 @@ import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; export const EmptyNftsCards = ( - len: number, + tokenArrayLength: number, ismobileTotalSquares: number, isWideScreenTotalSquares: number, isDesktopTotalSquares: number, @@ -10,16 +10,27 @@ export const EmptyNftsCards = ( const { isDesktop, isTablet, isWideScreen, isMobile } = useScreenSize(); let totalSquares = 0; + let totalSquaresX = 0; // Token quantity in X axis + // We are getting X count as the LCM to fill the rows with empty cards correctly. isMobile - ? (totalSquares = ismobileTotalSquares) + ? ((totalSquares = ismobileTotalSquares), + ismobileTotalSquares == 4 ? (totalSquaresX = 4) : (totalSquaresX = 3)) : isWideScreen - ? (totalSquares = isWideScreenTotalSquares) + ? ((totalSquares = isWideScreenTotalSquares), + isWideScreenTotalSquares == 8 ? (totalSquaresX = 4) : (totalSquaresX = 6)) : isDesktop - ? (totalSquares = isDesktopTotalSquares) - : isTablet && (totalSquares = isTabletTotalSquares); + ? ((totalSquares = isDesktopTotalSquares), (totalSquaresX = 6)) + : isTablet && ((totalSquares = isTabletTotalSquares), (totalSquaresX = 6)); - const emptySquaresCount = Math.max(totalSquares - len, 0); + const spareTokensX = tokenArrayLength % totalSquaresX; + const emptySquaresCountX = spareTokensX ? totalSquaresX - spareTokensX : 0; + + const spareTokens = totalSquares - tokenArrayLength; + const emptySquaresCount = + emptySquaresCountX < spareTokens + ? Math.max(spareTokens, 0) + : emptySquaresCountX; const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( <> diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index 30be759e..4c0184c6 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -19,7 +19,7 @@ interface INftsList { */ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { - const emptySquares = EmptyNftsCards(nftsList.length + 1, 15, 30, 30, 30); + const emptySquares = EmptyNftsCards(nftsList.length, 15, 30, 30, 30); const addTokenSquare = SwapAddTokenCard(); const nftSquares = nftsList.map((nft: NFT, index) => (
@@ -28,14 +28,15 @@ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { )); if (variant === "your") { - const allSquares = [...nftSquares, addTokenSquare, ...emptySquares]; + emptySquares.pop(); // Removes the last element to fill with addToken + const allSquares = [...nftSquares, ...emptySquares, addTokenSquare]; return (
{allSquares}
); } else { - const allSquares = [...emptySquares, ...nftSquares]; + const allSquares = [...nftSquares, ...emptySquares]; return (
{allSquares} From a1a8dffcdc0a0c6300fcebd7f4a57625687717f9 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 12:28:27 -0300 Subject: [PATCH 138/305] fix: word correction lenght to length --- components/02-molecules/ProgressStatus.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/components/02-molecules/ProgressStatus.tsx b/components/02-molecules/ProgressStatus.tsx index 734ee333..b30dd37d 100644 --- a/components/02-molecules/ProgressStatus.tsx +++ b/components/02-molecules/ProgressStatus.tsx @@ -1,5 +1,4 @@ -import { SwapContext } from "../01-atoms"; -import { ProgressBar } from "../01-atoms/ProgressBar"; +import { SwapContext, ProgressBar } from "@/components/01-atoms"; import { ADDRESS_ZERO } from "@/lib/client/constants"; import { useContext, useEffect, useState } from "react"; @@ -7,8 +6,8 @@ export const ProgressStatus = () => { const { authedUserSelectedNftsApprovalStatus } = useContext(SwapContext); const [ - authedUserSelectedApprovedItemsLenght, - setAuthedUserSelectedApprovalLenght, + authedUserSelectedApprovedItemsLength, + setAuthedUserSelectedApprovalLength, ] = useState(0); useEffect(() => { if (authedUserSelectedNftsApprovalStatus.length) { @@ -16,7 +15,7 @@ export const ProgressStatus = () => { (item) => item.approved !== ADDRESS_ZERO, ).length; - setAuthedUserSelectedApprovalLenght(approvedNftsCount); + setAuthedUserSelectedApprovalLength(approvedNftsCount); } }, [authedUserSelectedNftsApprovalStatus]); @@ -24,14 +23,14 @@ export const ProgressStatus = () => {

- {authedUserSelectedApprovedItemsLenght + + {authedUserSelectedApprovedItemsLength + "/" + authedUserSelectedNftsApprovalStatus.length}

From 85dada95bdc77940ebb59befaf48be16f7f51286 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 12:31:49 -0300 Subject: [PATCH 139/305] update: plus icon import to @/components --- components/01-atoms/SwapAddTokenCard.tsx | 9 ++++++--- components/01-atoms/index.ts | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/01-atoms/SwapAddTokenCard.tsx b/components/01-atoms/SwapAddTokenCard.tsx index 4d0ed910..3fa2faa6 100644 --- a/components/01-atoms/SwapAddTokenCard.tsx +++ b/components/01-atoms/SwapAddTokenCard.tsx @@ -1,5 +1,8 @@ -import { PlusIcon } from "./icons/PlusIcon"; -import { SwapAddManuallyModalLayout, Tooltip } from "@/components/01-atoms"; +import { + PlusIcon, + SwapAddManuallyModalLayout, + Tooltip, +} from "@/components/01-atoms"; import { useState } from "react"; export const SwapAddTokenCard = () => { const [open, setOpen] = useState(false); @@ -19,7 +22,7 @@ export const SwapAddTokenCard = () => { hover:bg-[#DDF23D20] transition-all duration-200 " - > + >
)} diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 37f40afe..ab47d021 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -84,7 +84,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? (
From 16416cbab458b7325c3c6e57780bf2ddd129a797 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:34:26 -0300 Subject: [PATCH 141/305] feat: add no scrollbar on global.css --- styles/global.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/styles/global.css b/styles/global.css index 0d0cef4f..03710dd0 100644 --- a/styles/global.css +++ b/styles/global.css @@ -15,6 +15,17 @@ input[type="search"]::-webkit-search-results-decoration { @tailwind utilities; @layer utilities { + /* Hide scrollbar for Chrome, Safari and Opera */ + .no-scrollbar::-webkit-scrollbar { + display: none; + } + + /* Hide scrollbar for IE, Edge and Firefox */ + .no-scrollbar { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } + .shadow-add-manually-card { box-shadow: 0px 0px 12px 1px #00000066; } From 5d69b842be44698732366a3c425f3660fd861ef1 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:36:00 -0300 Subject: [PATCH 142/305] update: add no scrollbar css in shelf & approved --- components/01-atoms/NftsCardApprovedList.tsx | 2 +- components/02-molecules/OfferSummary.tsx | 2 +- components/03-organisms/NftsShelf.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/01-atoms/NftsCardApprovedList.tsx b/components/01-atoms/NftsCardApprovedList.tsx index c4b105b9..52f3409a 100644 --- a/components/01-atoms/NftsCardApprovedList.tsx +++ b/components/01-atoms/NftsCardApprovedList.tsx @@ -107,7 +107,7 @@ export const NftsCardApprovedList = () => { return (
-
+
{nftAuthUser.map((nft, index) => (
{ )}
-
+
{(forAuthedUser && !authenticatedUserAddress?.address) || (!forAuthedUser && !validatedAddressToSwap) ? null : ( diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 37f40afe..d92710c0 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -84,7 +84,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? (
From d57c7ee93b317b18e753ebf528b94d25cab3b588 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:36:29 -0300 Subject: [PATCH 143/305] feat: add overflow-hidden in SwapModalLayout --- components/01-atoms/SwapModalLayout.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/01-atoms/SwapModalLayout.tsx b/components/01-atoms/SwapModalLayout.tsx index 9d31440c..2095036a 100644 --- a/components/01-atoms/SwapModalLayout.tsx +++ b/components/01-atoms/SwapModalLayout.tsx @@ -78,13 +78,15 @@ export const SwapModalLayout = ({

-
+

From 15c7139f6f26f759779bf3135a42ae776b084efa Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:37:33 -0300 Subject: [PATCH 144/305] feat: add SwapIcon with variant --- components/01-atoms/icons/SwapIcon.tsx | 70 +++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/components/01-atoms/icons/SwapIcon.tsx b/components/01-atoms/icons/SwapIcon.tsx index 918142fa..3e453ed3 100644 --- a/components/01-atoms/icons/SwapIcon.tsx +++ b/components/01-atoms/icons/SwapIcon.tsx @@ -1,7 +1,18 @@ import { SVGProps } from "react"; -export const SwapIcon = (props: SVGProps) => { - return ( +export enum SwapIconVariant { + VERTICAL = "vertical", + HORIZONTAL = "horizontal", +} +type SwapIconVariants = SwapIconVariant | "vertical" | "horizontal"; + +interface SwapIconProps { + props?: SVGProps; + variant?: SwapIconVariants; +} + +export const SwapIcon = ({ props, variant = "horizontal" }: SwapIconProps) => { + return variant == SwapIconVariant.HORIZONTAL ? ( ) => { + ) : ( + variant == SwapIconVariant.VERTICAL && ( + + + + + + + + + + + + + + + + + + ) ); }; From 34c44f222bf6b89044d89e2b2424840ed5f9532c Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:41:03 -0300 Subject: [PATCH 145/305] feat: add CardOffers with variant --- components/02-molecules/CardOffers.tsx | 105 +++++++++++++++++++------ 1 file changed, 80 insertions(+), 25 deletions(-) diff --git a/components/02-molecules/CardOffers.tsx b/components/02-molecules/CardOffers.tsx index 02e2d7e8..78593307 100644 --- a/components/02-molecules/CardOffers.tsx +++ b/components/02-molecules/CardOffers.tsx @@ -4,39 +4,94 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { EthereumAddress } from "@/lib/shared/types"; import { useContext } from "react"; +export enum CardOfferVariant { + DEFAULT = "default", + SECUNDARY = "secundary", +} + +type CardOfferVariants = CardOfferVariant | "default" | "secundary"; + interface CardOffersProps { address: EthereumAddress | null; + variant?: CardOfferVariants; +} + +interface CardOfferSConfig { + body: React.ReactNode; } -export const CardOffers = ({ address }: CardOffersProps) => { +export const CardOffers = ({ + address, + variant = "default", +}: CardOffersProps) => { const { authenticatedUserAddress } = useAuthenticatedUser(); const { nftAuthUser } = useContext(SwapContext); - return ( -

-
-
- + const DefaultVariant = () => { + return ( +
+
+
+ +
+
+ {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization +
+ {nftAuthUser.map((nft, index) => ( + + ))} +
+ )} +
+
+ +
-
- {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization -
- {nftAuthUser.map((nft, index) => ( - - ))} -
- )} -
-
- +
+ ); + }; + + const SecundaryVariant = () => { + return ( +
+
+
+ +
+
+ {authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization +
+ {nftAuthUser.map((nft, index) => ( + + ))} +
+ )} +
-
- ); + ); + }; + + const CardOfferVariantsConfig: Record = { + [CardOfferVariant.DEFAULT]: { + body: , + }, + [CardOfferVariant.SECUNDARY]: { + body: , + }, + }; + + return <>{CardOfferVariantsConfig[variant].body}; }; From d74031cb66972560434de7374872b11b4e971a1f Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:42:00 -0300 Subject: [PATCH 146/305] feat: add variant in UserOfferInfo --- components/02-molecules/UserOfferInfo.tsx | 42 +++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/components/02-molecules/UserOfferInfo.tsx b/components/02-molecules/UserOfferInfo.tsx index 9c3a57c3..16a3b25d 100644 --- a/components/02-molecules/UserOfferInfo.tsx +++ b/components/02-molecules/UserOfferInfo.tsx @@ -3,16 +3,27 @@ import { useEnsData } from "@/lib/client/hooks/useENSData"; import { collapseAddress } from "@/lib/client/utils"; import { EthereumAddress } from "@/lib/shared/types"; +export enum UserOfferVariant { + DEFAULT = "default", + SECUNDARY = "secundary", +} + +type UserOfferVariants = UserOfferVariant | "default" | "secundary"; + interface UserOfferInfoProps { address: EthereumAddress | null; + variant?: UserOfferVariants; } -export const UserOfferInfo = ({ address }: UserOfferInfoProps) => { +export const UserOfferInfo = ({ + address, + variant = "default", +}: UserOfferInfoProps) => { const { primaryName } = useEnsData({ ensAddress: address, }); const displayAddress = collapseAddress(address?.toString() ?? "") || ""; - return ( + return variant == UserOfferVariant.DEFAULT ? (
@@ -27,5 +38,32 @@ export const UserOfferInfo = ({ address }: UserOfferInfoProps) => {
+ ) : ( + variant === UserOfferVariant.SECUNDARY && ( +
+
+
+
+ {address && } +
+
+ {primaryName ? ( +

{primaryName} gets

+ ) : ( +

{displayAddress} gets

+ )} +
+
+
+

+ 0.1639 ETH {/* Should change to retrieve the value */} +

+

+   ($252.15) +

+
+
+
+ ) ); }; From 05e99d7ce34c6412d46701ca1bfe80c82ed58056 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:42:21 -0300 Subject: [PATCH 147/305] feat: add variant in TokenOffers --- components/03-organisms/TokenOffers.tsx | 60 ++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/components/03-organisms/TokenOffers.tsx b/components/03-organisms/TokenOffers.tsx index 29502531..fab5f7c6 100644 --- a/components/03-organisms/TokenOffers.tsx +++ b/components/03-organisms/TokenOffers.tsx @@ -3,11 +3,26 @@ import { TokenOfferDetails, SwapIcon } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import cc from "classcat"; -export const TokenOffers = () => { +export enum TokenOfferVariant { + HORIZONTAL = "horizontal", + VERTICAL = "vertical", +} + +type TokenOfferVariants = TokenOfferVariant | "horizontal" | "vertical"; + +interface TokenOffersProps { + variant?: TokenOfferVariants; +} + +interface TokenOffersConfig { + body: React.ReactNode; +} + +export const TokenOffers = ({ variant = "horizontal" }: TokenOffersProps) => { const { authenticatedUserAddress } = useAuthenticatedUser(); - return ( - <> + const HorizontalVariant = () => { + return (
@@ -24,6 +39,41 @@ export const TokenOffers = () => {
- - ); + ); + }; + + const VerticalVariant = () => { + return ( +
+
+
+ +
+
+ +
+
+ +
+
+
+ ); + }; + + const TokenOffersPropsConfig: Record = { + [TokenOfferVariant.HORIZONTAL]: { + body: , + }, + [TokenOfferVariant.VERTICAL]: { + body: , + }, + }; + + return <>{TokenOffersPropsConfig[variant].body}; }; From 0b43d6ee7e031a762431a2e673ecdf9e8aafa78d Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:42:51 -0300 Subject: [PATCH 148/305] feat: add tokenOffer variant vertical in ConfirmSwapModal --- components/02-molecules/ConfirmSwapModal.tsx | 30 +++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/components/02-molecules/ConfirmSwapModal.tsx b/components/02-molecules/ConfirmSwapModal.tsx index 461df4a0..94de00d9 100644 --- a/components/02-molecules/ConfirmSwapModal.tsx +++ b/components/02-molecules/ConfirmSwapModal.tsx @@ -6,7 +6,7 @@ import { SwapContext, SwapModalButton, SwapModalLayout, - OfferExpiryConfirmSwap + OfferExpiryConfirmSwap, } from "@/components/01-atoms"; import { ProgressStatus } from "@/components/02-molecules"; import { createSwap } from "@/lib/service/createSwap"; @@ -17,6 +17,7 @@ import { SwapModalSteps, } from "@/lib/client/blockchain-data"; import { updateNftsToSwapApprovalStatus } from "@/lib/client/swap-utils"; +import { TokenOffers } from "@/components/03-organisms"; import { useNetwork, useWalletClient } from "wagmi"; import { useContext, useEffect } from "react"; import { useTheme } from "next-themes"; @@ -174,7 +175,14 @@ export const ConfirmSwapModal = ({ description: "Please review your final proposal.", }} body={{ - component: , + component: ( + <> +
+ + +
+ + ), }} footer={{ component: ( @@ -210,7 +218,14 @@ export const ConfirmSwapModal = ({ description: "Please review your final proposal.", }} body={{ - component: , + component: ( + <> +
+ + +
+ + ), }} footer={{ component: ( @@ -236,7 +251,14 @@ export const ConfirmSwapModal = ({ description: "Congrats, your swap offer was submitted.", }} body={{ - component: , + component: ( + <> +
+ + +
+ + ), }} footer={{ component: ( From efe45c49ff6091000aabea20cf5af5997c11f8cb Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 17:50:57 -0300 Subject: [PATCH 149/305] update: word correction secundary -> secondary --- components/02-molecules/CardOffers.tsx | 8 ++++---- components/02-molecules/UserOfferInfo.tsx | 6 +++--- components/03-organisms/TokenOffers.tsx | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/02-molecules/CardOffers.tsx b/components/02-molecules/CardOffers.tsx index 78593307..241fd84a 100644 --- a/components/02-molecules/CardOffers.tsx +++ b/components/02-molecules/CardOffers.tsx @@ -6,10 +6,10 @@ import { useContext } from "react"; export enum CardOfferVariant { DEFAULT = "default", - SECUNDARY = "secundary", + SECONDARY = "secondary", } -type CardOfferVariants = CardOfferVariant | "default" | "secundary"; +type CardOfferVariants = CardOfferVariant | "default" | "secondary"; interface CardOffersProps { address: EthereumAddress | null; @@ -62,7 +62,7 @@ export const CardOffers = ({
- +
{authenticatedUserAddress && ( // That div needs change to render the given Tokens by Subgraph, shouldn't be the , for now, just visualization @@ -88,7 +88,7 @@ export const CardOffers = ({ [CardOfferVariant.DEFAULT]: { body: , }, - [CardOfferVariant.SECUNDARY]: { + [CardOfferVariant.SECONDARY]: { body: , }, }; diff --git a/components/02-molecules/UserOfferInfo.tsx b/components/02-molecules/UserOfferInfo.tsx index 16a3b25d..a18fc0c3 100644 --- a/components/02-molecules/UserOfferInfo.tsx +++ b/components/02-molecules/UserOfferInfo.tsx @@ -5,10 +5,10 @@ import { EthereumAddress } from "@/lib/shared/types"; export enum UserOfferVariant { DEFAULT = "default", - SECUNDARY = "secundary", + SECONDARY = "secondary", } -type UserOfferVariants = UserOfferVariant | "default" | "secundary"; +type UserOfferVariants = UserOfferVariant | "default" | "secondary"; interface UserOfferInfoProps { address: EthereumAddress | null; @@ -39,7 +39,7 @@ export const UserOfferInfo = ({
) : ( - variant === UserOfferVariant.SECUNDARY && ( + variant === UserOfferVariant.SECONDARY && (
diff --git a/components/03-organisms/TokenOffers.tsx b/components/03-organisms/TokenOffers.tsx index fab5f7c6..75cd1d3f 100644 --- a/components/03-organisms/TokenOffers.tsx +++ b/components/03-organisms/TokenOffers.tsx @@ -49,13 +49,13 @@ export const TokenOffers = ({ variant = "horizontal" }: TokenOffersProps) => {
From 965bcff9b09f732037e6b36591e9ad58847559af Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 18:42:49 -0300 Subject: [PATCH 150/305] update: tooltip classname for greater readability --- components/01-atoms/Tooltip.tsx | 60 +++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/components/01-atoms/Tooltip.tsx b/components/01-atoms/Tooltip.tsx index 52d2033b..97e0fe3e 100644 --- a/components/01-atoms/Tooltip.tsx +++ b/components/01-atoms/Tooltip.tsx @@ -10,31 +10,35 @@ enum ToolTipPosition { type Position = ToolTipPosition | "top" | "bottom" | "left" | "right"; -interface IToolTip { +interface TooltipProps { position: Position; content: string; children?: React.ReactNode; } -export const Tooltip = ({ position, content, children }: IToolTip) => ( +export const Tooltip = ({ position, content, children }: TooltipProps) => (
{children}
From e04ea86dd919ebe0cf7d6b503027412570e3788d Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 19:44:57 -0300 Subject: [PATCH 151/305] update: globals.css to input autofill bg --- styles/global.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/styles/global.css b/styles/global.css index 34f520da..bfb6d4cf 100644 --- a/styles/global.css +++ b/styles/global.css @@ -9,6 +9,15 @@ input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { display: none; } +/* Change Autocomplete styles in Chrome*/ +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus { + font-size: inherit; + -webkit-text-fill-color: none; + -webkit-box-shadow: 0 0 0px 1000px transparent inset; + transition: background-color 5000s ease-in-out 0s; +} @tailwind base; @tailwind components; From 8331fd61344cab969d790a669708b71723ddfdaf Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Mon, 26 Feb 2024 19:47:02 -0300 Subject: [PATCH 152/305] update: console.log to console.error --- components/01-atoms/SearchBar.tsx | 60 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index ffdef78a..78977d38 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -10,8 +10,12 @@ import cc from "classcat"; import Web3 from "web3"; export const SearchBar = () => { - const { setInputAddress, inputAddress, validateAddressToSwap, setUserJustValidatedInput } = - useContext(SwapContext); + const { + setInputAddress, + inputAddress, + validateAddressToSwap, + setUserJustValidatedInput, + } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -20,10 +24,10 @@ export const SearchBar = () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars const validateUser = (ensNameAddress: string | null) => { - if (!authenticatedUserAddress) return + if (!authenticatedUserAddress) return; validateAddressToSwap(authenticatedUserAddress, ensNameAddress); - } + }; const getUserAddress = async () => { if (inputAddress) { @@ -39,44 +43,36 @@ export const SearchBar = () => { const ens = new ENS(undefined, provider); - const formattedAddress = - inputAddress.toLowerCase().includes(".") - ? inputAddress.toLowerCase().includes(".eth") - ? inputAddress.split(".")[1].length >= 3 - ? inputAddress - : `${inputAddress.split(".")[0]}.eth` - : inputAddress.split(".")[1].length >= 3 - ? inputAddress - : `${inputAddress.split(".")[0]}.eth` - : `${inputAddress}.eth`; + const formattedAddress = inputAddress.toLowerCase().includes(".") + ? inputAddress.toLowerCase().includes(".eth") + ? inputAddress.split(".")[1].length >= 3 + ? inputAddress + : `${inputAddress.split(".")[0]}.eth` + : inputAddress.split(".")[1].length >= 3 + ? inputAddress + : `${inputAddress.split(".")[0]}.eth` + : `${inputAddress}.eth`; try { const address: unknown = await ens.getOwner(formattedAddress); - if (typeof address !== "string") return + if (typeof address !== "string") return; validateUser(address); - - } - catch (e) { - console.log(e); - } - finally { + } catch (e) { + console.error(e); + } finally { setUserJustValidatedInput(true); } } - } + }; useEffect(() => { - const requestDelay = setTimeout(() => { - setUserJustValidatedInput(false); getUserAddress(); - }, 2000); return () => clearTimeout(requestDelay); - }, [inputAddress]); return ( @@ -86,15 +82,15 @@ export const SearchBar = () => { Who are you swapping with today?
-
+
Date: Mon, 26 Feb 2024 21:19:34 -0300 Subject: [PATCH 153/305] fix: when searching the seame address twice, now the error message not display and inventory items display. --- components/01-atoms/SearchBar.tsx | 3 ++- components/01-atoms/SwapContext.tsx | 4 ++++ components/03-organisms/NftsShelf.tsx | 16 ++++++---------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 78977d38..9f3d0a64 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -15,6 +15,7 @@ export const SearchBar = () => { inputAddress, validateAddressToSwap, setUserJustValidatedInput, + setValidatedAddressToSwap } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -67,9 +68,9 @@ export const SearchBar = () => { }; useEffect(() => { + setValidatedAddressToSwap(""); const requestDelay = setTimeout(() => { setUserJustValidatedInput(false); - getUserAddress(); }, 2000); return () => clearTimeout(requestDelay); diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index 75e12989..d1fc73ed 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -15,6 +15,7 @@ import toast from "react-hot-toast"; interface SwapContextProps { inputAddress: string; validatedAddressToSwap: string; + setValidatedAddressToSwap: (address: string) => void setInputAddress: (address: string) => void; validateAddressToSwap: ( authedUser: EthereumAddress, @@ -43,6 +44,7 @@ interface SwapContextProps { export const SwapContext = React.createContext({ inputAddress: "", validatedAddressToSwap: "", + setValidatedAddressToSwap: () => {}, validateAddressToSwap: ( _authedUser: EthereumAddress, _inputEnsAddress: string | null | undefined, @@ -178,6 +180,7 @@ export const SwapContextProvider = ({ children }: any) => { inputAddress, setInputAddress, validatedAddressToSwap, + setValidatedAddressToSwap, validateAddressToSwap, setUserJustValidatedInput, userJustValidatedInput, @@ -213,6 +216,7 @@ export const SwapContextProvider = ({ children }: any) => { inputAddress, setInputAddress, validatedAddressToSwap, + setValidatedAddressToSwap, validateAddressToSwap, setUserJustValidatedInput, userJustValidatedInput, diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 6cc989da..a2a1f20a 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -29,18 +29,14 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { const { theme } = useTheme(); const { authenticatedUserAddress } = useAuthenticatedUser(); - const { validatedAddressToSwap, inputAddress, destinyChain, userJustValidatedInput } = - useContext(SwapContext); - - const [addressSearchCount, setAddressSearchCount] = useState(0) + const { validatedAddressToSwap, inputAddress, destinyChain } = useContext(SwapContext); const showUserItems = async () => { const chainId = address === authenticatedUserAddress?.address ? chain?.id : ChainInfo[destinyChain].id; - if(addressSearchCount > 1) return //When a new address is added, all useEffect parameters are updated - // addressSearchCount prevents multiple API calls from occurring, causing undesired behavior to occur. + if (address && chainId && inputAddress) { try { const nftsList = await getNftsFrom(address, chainId, setNftsQueryStatus) @@ -52,15 +48,14 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { setNftsList([]); } - setAddressSearchCount((prev)=> prev + 1) } } useEffect(() => { showUserItems() - console.log(userJustValidatedInput) - }, [address, chain, destinyChain, userJustValidatedInput]); + console.log("ok") + }, [address, chain, destinyChain]); useEffect(() => { if ( @@ -81,6 +76,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { }, [chain]); useEffect(() => { + if ( address !== authenticatedUserAddress?.address && validatedAddressToSwap !== authenticatedUserAddress?.address || !inputAddress @@ -88,7 +84,7 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } - setAddressSearchCount(0) + }, [inputAddress]); useEffect(() => { From d632c2aa77f1b266d5afc3848f39ef46083c8742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 00:27:00 -0300 Subject: [PATCH 154/305] fix: when searching the seame address twice, now the error message not display and inventory items display. --- components/01-atoms/SearchBar.tsx | 1 - components/01-atoms/SwapContext.tsx | 7 ++++++- components/03-organisms/NftsShelf.tsx | 5 ----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 9f3d0a64..f9803408 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -21,7 +21,6 @@ export const SearchBar = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); const { theme } = useTheme(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars const validateUser = (ensNameAddress: string | null) => { diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index d1fc73ed..3f714be5 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -11,6 +11,7 @@ import { } from "@/lib/client/blockchain-data"; import React, { Dispatch, useEffect, useState } from "react"; import toast from "react-hot-toast"; +import { useRouter } from "next/router"; interface SwapContextProps { inputAddress: string; @@ -87,7 +88,7 @@ export const SwapContextProvider = ({ children }: any) => { authedUserSelectedNftsApprovalStatus, setAuthedUserNftsApprovalStatus, ] = useState([]); - + const router = useRouter() const validateAddressToSwap = ( _authedUser: EthereumAddress, _inputEnsAddress: string | null | undefined, @@ -236,6 +237,10 @@ export const SwapContextProvider = ({ children }: any) => { currentSwapModalStep, }); + useEffect(()=>{ + setValidatedAddressToSwap(""); + },[router.asPath]) + return ( {children} ); diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index a2a1f20a..fe8d4150 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -47,14 +47,11 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { setNftsList([]); } - } - } useEffect(() => { showUserItems() - console.log("ok") }, [address, chain, destinyChain]); useEffect(() => { @@ -76,7 +73,6 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { }, [chain]); useEffect(() => { - if ( address !== authenticatedUserAddress?.address && validatedAddressToSwap !== authenticatedUserAddress?.address || !inputAddress @@ -84,7 +80,6 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } - }, [inputAddress]); useEffect(() => { From de2d62e45894b5d9e5216e7d8c1af9c2e004a26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 03:21:41 -0300 Subject: [PATCH 155/305] fix: when searching the seame address twice, now the error message not display and inventory items display. --- components/01-atoms/SearchBar.tsx | 2 +- components/03-organisms/NftsShelf.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index f9803408..f71d1299 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -107,4 +107,4 @@ export const SearchBar = () => {
); -}; +}; \ No newline at end of file diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index fe8d4150..e182460c 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -131,4 +131,4 @@ export const NftsShelf = ({ address }: INftsShelfProps) => { ) : null}
); -}; +}; \ No newline at end of file From 1a77bfdd0b0ec3141c4f9dcfea5c2157cc79c91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 04:57:38 -0300 Subject: [PATCH 156/305] fix/send nft token to correctly OfferSummary component and OffersSummary show users image next to the address --- components/02-molecules/OfferSummary.tsx | 29 ++++++++++++------------ components/03-organisms/SwapStation.tsx | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index c0f9b7d3..6a2d1c8e 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -1,7 +1,7 @@ import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { NftCard } from "@/components/02-molecules"; -import { EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; +import { ENSAvatar, EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; import { useContext } from "react"; interface IOfferSummary { @@ -9,7 +9,7 @@ interface IOfferSummary { } export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { - const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress, userJustValidatedInput } = + const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -21,29 +21,30 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { 12, 12, ); - - const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; - + const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; return (
- + {!forAuthedUser && authenticatedUserAddress ? + + : forAuthedUser && validatedAddressToSwap ? + + : }

{ - forAuthedUser - ? "You give" - : !forAuthedUser && validatedAddressToSwap && inputAddress - ? `${userJustValidatedInput ? - new EthereumAddress(validatedAddressToSwap).getEllipsedAddress() + " gives" - : "Use the search bar!" - }` - : "Use the search bar!" + !forAuthedUser && authenticatedUserAddress ? + `${new EthereumAddress(authenticatedUserAddress.address).getEllipsedAddress()} gets` : + !forAuthedUser ? `You Get` : + forAuthedUser && validatedAddressToSwap && inputAddress ? + `${new EthereumAddress(validatedAddressToSwap).getEllipsedAddress()} gets` : + forAuthedUser && !validatedAddressToSwap || !inputAddress ? + `Use the search bar` : `Use the search bar` }

diff --git a/components/03-organisms/SwapStation.tsx b/components/03-organisms/SwapStation.tsx index 4910fec0..585f5643 100644 --- a/components/03-organisms/SwapStation.tsx +++ b/components/03-organisms/SwapStation.tsx @@ -56,8 +56,8 @@ export const SwapStation = () => {
- +
From 5fbe7823d3cf3cf3c89e8ea0f0ca2beae07f5113 Mon Sep 17 00:00:00 2001 From: Andre-Dev Date: Tue, 27 Feb 2024 10:08:59 -0300 Subject: [PATCH 157/305] adjusting TheHeader position --- components/04-templates/SwapSection.tsx | 2 +- pages/offers.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index b5fa79cf..275661f7 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -4,7 +4,7 @@ import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( -
+
diff --git a/pages/offers.tsx b/pages/offers.tsx index 3757d51f..5bf6a8c3 100644 --- a/pages/offers.tsx +++ b/pages/offers.tsx @@ -12,7 +12,7 @@ export default function Offers() { {authenticatedUserAddress && (
From 2c9ddace9b477b4afdc64b689c74fcba5c279c51 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 12:33:51 -0300 Subject: [PATCH 158/305] update: click on background and close the sidebar --- components/01-atoms/WalletSidebarTemplate.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/01-atoms/WalletSidebarTemplate.tsx b/components/01-atoms/WalletSidebarTemplate.tsx index 02e0655e..bed40605 100644 --- a/components/01-atoms/WalletSidebarTemplate.tsx +++ b/components/01-atoms/WalletSidebarTemplate.tsx @@ -1,4 +1,5 @@ import { TheSidebarHeader, UserInfo } from "@/components/02-molecules"; +import { useSidebar } from "@/lib/client/contexts/SidebarContext.tsx"; import React from "react"; import cc from "classcat"; import { useTheme } from "next-themes"; @@ -15,14 +16,17 @@ export const WalletSidebarTemplate = ({ const { systemTheme, theme } = useTheme(); const currentTheme = theme === "system" ? systemTheme : theme; const isDark = currentTheme === "dark"; + const { toggleSidebar } = useSidebar(); return ( <>
Date: Tue, 27 Feb 2024 14:34:38 -0300 Subject: [PATCH 159/305] fix: state of empty cards --- components/02-molecules/OfferSummary.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index bccf2d02..f9a7e72e 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -17,6 +17,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { }); const { authenticatedUserAddress } = useAuthenticatedUser(); + const emptySquaresDefault = EmptyNftsCards(0, 4, 8, 12, 12); const emptySquaresAuthUser = EmptyNftsCards(nftAuthUser.length, 4, 8, 12, 12); const emptySquaresInputUser = EmptyNftsCards( nftInputUser.length, @@ -78,11 +79,14 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { nftData={nft} /> ))} - - {forAuthedUser && emptySquaresAuthUser} - {!forAuthedUser && emptySquaresInputUser} )} + + {forAuthedUser + ? emptySquaresAuthUser + : !forAuthedUser + ? emptySquaresInputUser + : emptySquaresDefault}
From ac08c690527f16b4baa78ee52d510aa1281907bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 14:36:55 -0300 Subject: [PATCH 160/305] feat/when the address has a user name, the OfferSummary shows the username instead the address. --- components/02-molecules/OfferSummary.tsx | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 6a2d1c8e..90386c35 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -2,7 +2,9 @@ import { EthereumAddress } from "@/lib/shared/types"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { NftCard } from "@/components/02-molecules"; import { ENSAvatar, EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; -import { useContext } from "react"; +import { useEnsData } from "@/lib/client/hooks/useENSData"; +import { useContext, useEffect } from "react"; + interface IOfferSummary { forAuthedUser: boolean; @@ -24,13 +26,24 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; + const { primaryName: name1 } = useEnsData({ + ensAddress: authenticatedUserAddress + }) + const { primaryName: name2 } = useEnsData({ + ensAddress: validatedAddressToSwap as unknown as EthereumAddress + }) + + useEffect(()=>{ + console.log(new EthereumAddress(validatedAddressToSwap)) + },[validatedAddressToSwap]) + return (
{!forAuthedUser && authenticatedUserAddress ? - + : forAuthedUser && validatedAddressToSwap ? : } @@ -38,13 +51,17 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {

{ - !forAuthedUser && authenticatedUserAddress ? - `${new EthereumAddress(authenticatedUserAddress.address).getEllipsedAddress()} gets` : - !forAuthedUser ? `You Get` : - forAuthedUser && validatedAddressToSwap && inputAddress ? - `${new EthereumAddress(validatedAddressToSwap).getEllipsedAddress()} gets` : - forAuthedUser && !validatedAddressToSwap || !inputAddress ? - `Use the search bar` : `Use the search bar` + !forAuthedUser && authenticatedUserAddress && name1 ? + `${name1} gets` : + !forAuthedUser && authenticatedUserAddress ? + `${new EthereumAddress(authenticatedUserAddress.address).getEllipsedAddress()} gets` : + !forAuthedUser ? `You Get` : + forAuthedUser && validatedAddressToSwap && inputAddress && name2 ? + `${name2} gets` : + forAuthedUser && validatedAddressToSwap && inputAddress + ? `${new EthereumAddress(validatedAddressToSwap).getEllipsedAddress()} gets` : + forAuthedUser && !validatedAddressToSwap || !inputAddress ? + `Use the search bar` : `Use the search bar` }

From 23eb2857fcf014dd8d0ce6728e1a5515075d4601 Mon Sep 17 00:00:00 2001 From: 0xneves Date: Wed, 28 Feb 2024 00:45:57 +0700 Subject: [PATCH 161/305] fix: wrong alignment for address in walletSidebarTemplate --- components/02-molecules/EnsNameAndAddressWallet.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/02-molecules/EnsNameAndAddressWallet.tsx b/components/02-molecules/EnsNameAndAddressWallet.tsx index fa69c840..cfbaf9a9 100644 --- a/components/02-molecules/EnsNameAndAddressWallet.tsx +++ b/components/02-molecules/EnsNameAndAddressWallet.tsx @@ -25,7 +25,7 @@ export const EnsNameAndAddressWallet = () => { <>
-
+
{primaryName && ( <>

{`${primaryName}`}

@@ -40,7 +40,7 @@ export const EnsNameAndAddressWallet = () => { authenticatedUserAddress.toString(), ); }} - className="flex items-center justify-start gap-1" + className="flex items-center justify-start gap-2" >

{` ${displayAddress}`}

From 2c430577f4a84a844a1a00946aafdac5d419fe4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 15:01:12 -0300 Subject: [PATCH 162/305] feat/when the address has a user name, the OfferSummary shows the username instead the address. --- components/02-molecules/OfferSummary.tsx | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 90386c35..2fced868 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -3,7 +3,7 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { NftCard } from "@/components/02-molecules"; import { ENSAvatar, EmptyNftsCards, PersonIcon, SwapContext } from "@/components/01-atoms"; import { useEnsData } from "@/lib/client/hooks/useENSData"; -import { useContext, useEffect } from "react"; +import { useContext, useEffect, useState } from "react"; interface IOfferSummary { @@ -11,7 +11,7 @@ interface IOfferSummary { } export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { - const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress } = + const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress, userJustValidatedInput } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -25,16 +25,24 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { ); const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; + const [searchedEthereumAdress, setSearchedEthereumAddress] = useState(null) - const { primaryName: name1 } = useEnsData({ + const { primaryName: walletENSName } = useEnsData({ ensAddress: authenticatedUserAddress }) - const { primaryName: name2 } = useEnsData({ - ensAddress: validatedAddressToSwap as unknown as EthereumAddress + const { primaryName: searchedENSName } = useEnsData({ + ensAddress: searchedEthereumAdress as unknown as EthereumAddress }) + + useEffect(()=>{ - console.log(new EthereumAddress(validatedAddressToSwap)) + if(!validatedAddressToSwap && !userJustValidatedInput) return + + const newAddress = new EthereumAddress(validatedAddressToSwap) + setSearchedEthereumAddress(newAddress); + + // eslint-disable-next-line react-hooks/exhaustive-deps },[validatedAddressToSwap]) return ( @@ -51,13 +59,13 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {

{ - !forAuthedUser && authenticatedUserAddress && name1 ? - `${name1} gets` : + !forAuthedUser && authenticatedUserAddress && walletENSName ? + `${walletENSName} gets` : !forAuthedUser && authenticatedUserAddress ? `${new EthereumAddress(authenticatedUserAddress.address).getEllipsedAddress()} gets` : !forAuthedUser ? `You Get` : - forAuthedUser && validatedAddressToSwap && inputAddress && name2 ? - `${name2} gets` : + forAuthedUser && validatedAddressToSwap && inputAddress && searchedENSName ? + `${searchedENSName} gets` : forAuthedUser && validatedAddressToSwap && inputAddress ? `${new EthereumAddress(validatedAddressToSwap).getEllipsedAddress()} gets` : forAuthedUser && !validatedAddressToSwap || !inputAddress ? From aa6a7230d61e326461ad4ad4c86557871ec91109 Mon Sep 17 00:00:00 2001 From: Rafael Sanches Date: Tue, 27 Feb 2024 16:06:54 -0300 Subject: [PATCH 163/305] feat: added SearchItemsShelf atom to be the search for tor the SwappingShelfs organism --- components/01-atoms/SearchItemsShelf.tsx | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 components/01-atoms/SearchItemsShelf.tsx diff --git a/components/01-atoms/SearchItemsShelf.tsx b/components/01-atoms/SearchItemsShelf.tsx new file mode 100644 index 00000000..4af4144c --- /dev/null +++ b/components/01-atoms/SearchItemsShelf.tsx @@ -0,0 +1,32 @@ +import { MagnifyingGlassIcon } from "@/components/01-atoms/icons/MagnifyingGlassIcon"; +import { useTheme } from "next-themes"; +import cc from "classcat"; + +export const SearchItemsShelf = () => { + const { theme } = useTheme(); + + return ( +

+ +
+ +
+
+ ); +}; From d67321b1ed1e4bdd6b1e6eadf0939db2843c1960 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 16:22:26 -0300 Subject: [PATCH 164/305] update: adjusting size of all components in dApp - initial structure --- components/01-atoms/SearchBar.tsx | 2 +- components/02-molecules/NftsList.tsx | 6 ++-- components/02-molecules/TheHeader.tsx | 36 ++++++++++++++++------ components/03-organisms/NftsShelf.tsx | 12 +++++--- components/03-organisms/SwappingShelfs.tsx | 7 +++-- components/04-templates/SwapSection.tsx | 33 ++++++++++++++------ pages/index.tsx | 14 ++++----- 7 files changed, 74 insertions(+), 36 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index 78977d38..5937c2ff 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -76,7 +76,7 @@ export const SearchBar = () => { }, [inputAddress]); return ( -
+

Who are you swapping with today? diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index 4c0184c6..bbdae05e 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -19,7 +19,7 @@ interface INftsList { */ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { - const emptySquares = EmptyNftsCards(nftsList.length, 15, 30, 30, 30); + const emptySquares = EmptyNftsCards(nftsList.length, 15, 24, 24, 24); const addTokenSquare = SwapAddTokenCard(); const nftSquares = nftsList.map((nft: NFT, index) => (
@@ -31,14 +31,14 @@ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { emptySquares.pop(); // Removes the last element to fill with addToken const allSquares = [...nftSquares, ...emptySquares, addTokenSquare]; return ( -
+
{allSquares}
); } else { const allSquares = [...nftSquares, ...emptySquares]; return ( -
+
{allSquares}
); diff --git a/components/02-molecules/TheHeader.tsx b/components/02-molecules/TheHeader.tsx index 11bc40d1..e7ee6ba0 100644 --- a/components/02-molecules/TheHeader.tsx +++ b/components/02-molecules/TheHeader.tsx @@ -32,7 +32,7 @@ export const TheHeader = () => { const isDark = currentTheme === "dark"; return ( <> -
+
{
{isDark ? ( - 1440 ? "right" : "bottom"} content={"Light Mode"}> - ) : ( - 1440 ? "right" : "bottom"} content={"Dark Mode"}> + 1440 ? "right" : "bottom"} + content={"Dark Mode"} + > )} @@ -70,7 +76,10 @@ export const TheHeader = () => { {isWideScreen ? ( <> {!!authenticatedUserAddress ? ( - 1440 ? "right" : "bottom"} content={"Your wallet"}> + 1440 ? "right" : "bottom"} + content={"Your wallet"} + > ) : ( - 1440 ? "right" : "bottom"} content={"Connect a Wallet"}> + 1440 ? "right" : "bottom"} + content={"Connect a Wallet"} + >
{ ) : ( <> {!!authenticatedUserAddress ? ( - 1440 ? "right" : "bottom"} content={"Your wallet"}> + 1440 ? "right" : "bottom"} + content={"Your wallet"} + > ) : ( - 1440 ? "right" : "bottom"} content={"Connect a Wallet"}> + 1440 ? "right" : "bottom"} + content={"Connect a Wallet"} + >
{ }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? ( -
- +
+
) : nftsQueryStatus == NFTsQueryStatus.EMPTY_QUERY || !address ? ( -
+
{ }, [chain]); return ( -
+
setActiveSwappingShelfID(input)} /> @@ -41,7 +41,10 @@ export const SwappingShelfs = () => {
- +
); diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 275661f7..57722a59 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -4,15 +4,28 @@ import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( -
-
- -
-
- - -
- -
+ //
+ // + //
+ // + // + //
+ // + //
+ +
+ +
+
+
+ + +
+
+ +
+
+
+
); }; diff --git a/pages/index.tsx b/pages/index.tsx index e39c45f9..de56fd13 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -4,13 +4,13 @@ import cc from "classcat"; export default function IndexPage() { return ( -
- -
+
+ +
); } From b9bfe17a0c2259c4b7b712cdf7a7b80150eee155 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 16:34:06 -0300 Subject: [PATCH 165/305] fix: word correction secundary -> secondary --- components/02-molecules/CardOffers.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/02-molecules/CardOffers.tsx b/components/02-molecules/CardOffers.tsx index 241fd84a..4d3a2ac9 100644 --- a/components/02-molecules/CardOffers.tsx +++ b/components/02-molecules/CardOffers.tsx @@ -57,7 +57,7 @@ export const CardOffers = ({ ); }; - const SecundaryVariant = () => { + const SecondaryVariant = () => { return (
@@ -89,7 +89,7 @@ export const CardOffers = ({ body: , }, [CardOfferVariant.SECONDARY]: { - body: , + body: , }, }; From 7373611147efb0cc20cb2e8d5e5aaa5ac32265bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Tue, 27 Feb 2024 18:33:44 -0300 Subject: [PATCH 166/305] fix/now your items showing correctly after value of input changes --- components/03-organisms/NftsShelf.tsx | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 00f0d449..91ad5d55 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -11,7 +11,7 @@ import { useNetwork } from "wagmi"; interface INftsShelfProps { address: string | null; - variant: "your" | "their"; + variant: "your" | "their" } /** @@ -30,16 +30,17 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { const { theme } = useTheme(); const { authenticatedUserAddress } = useAuthenticatedUser(); - const { validatedAddressToSwap, inputAddress, destinyChain } = useContext(SwapContext); + const { validatedAddressToSwap, destinyChain } = useContext(SwapContext); const showUserItems = async () => { const chainId = address === authenticatedUserAddress?.address ? chain?.id : ChainInfo[destinyChain].id; - - if (address && chainId && inputAddress) { + + if (address && chainId) { try { + console.log("ok") const nftsList = await getNftsFrom(address, chainId, setNftsQueryStatus) setNftsList(nftsList); @@ -74,26 +75,16 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { }, [chain]); useEffect(() => { - if ( - address !== authenticatedUserAddress?.address && - validatedAddressToSwap !== authenticatedUserAddress?.address || !inputAddress - ) { - setNftsList([]); - setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); - } - }, [inputAddress]); - - useEffect(() => { - if (!validatedAddressToSwap) { + if (!validatedAddressToSwap && address !== authenticatedUserAddress?.address) { setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } - }, [validatedAddressToSwap]); + }, [validatedAddressToSwap, address]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? (
- +
) : nftsQueryStatus == NFTsQueryStatus.EMPTY_QUERY || !address ? (
From 6ad03699beab832f87adc14baf9d4a2b5b065cf2 Mon Sep 17 00:00:00 2001 From: 0xneves Date: Wed, 28 Feb 2024 06:37:06 +0700 Subject: [PATCH 167/305] fix: repository missing items when duplicated names is inputed --- components/01-atoms/SearchBar.tsx | 6 ++-- components/01-atoms/SwapContext.tsx | 10 +++--- components/03-organisms/NftsShelf.tsx | 42 +++++++++++++--------- components/03-organisms/SwappingShelfs.tsx | 5 ++- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index f71d1299..e2d1cd8b 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -15,7 +15,7 @@ export const SearchBar = () => { inputAddress, validateAddressToSwap, setUserJustValidatedInput, - setValidatedAddressToSwap + setValidatedAddressToSwap, } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -71,7 +71,7 @@ export const SearchBar = () => { const requestDelay = setTimeout(() => { setUserJustValidatedInput(false); getUserAddress(); - }, 2000); + }, 750); return () => clearTimeout(requestDelay); }, [inputAddress]); @@ -107,4 +107,4 @@ export const SearchBar = () => {
); -}; \ No newline at end of file +}; diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index 3f714be5..3398789e 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -16,7 +16,7 @@ import { useRouter } from "next/router"; interface SwapContextProps { inputAddress: string; validatedAddressToSwap: string; - setValidatedAddressToSwap: (address: string) => void + setValidatedAddressToSwap: (address: string) => void; setInputAddress: (address: string) => void; validateAddressToSwap: ( authedUser: EthereumAddress, @@ -88,7 +88,7 @@ export const SwapContextProvider = ({ children }: any) => { authedUserSelectedNftsApprovalStatus, setAuthedUserNftsApprovalStatus, ] = useState([]); - const router = useRouter() + const router = useRouter(); const validateAddressToSwap = ( _authedUser: EthereumAddress, _inputEnsAddress: string | null | undefined, @@ -237,9 +237,11 @@ export const SwapContextProvider = ({ children }: any) => { currentSwapModalStep, }); - useEffect(()=>{ + // This is a temporary measure while we don't turn the dApp into a SPA + // We are reseting the inputAddress to reload the inventory + useEffect(() => { setValidatedAddressToSwap(""); - },[router.asPath]) + }, [router.asPath]); return ( {children} diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 00f0d449..70be1b75 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { NFT, ChainInfo, NFTsQueryStatus, } from "@/lib/client/constants"; +import { NFT, ChainInfo, NFTsQueryStatus } from "@/lib/client/constants"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { EthereumAddress } from "@/lib/shared/types"; import { SelectUserIcon, SwapContext } from "@/components/01-atoms"; @@ -30,36 +30,40 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { const { theme } = useTheme(); const { authenticatedUserAddress } = useAuthenticatedUser(); - const { validatedAddressToSwap, inputAddress, destinyChain } = useContext(SwapContext); + const { validatedAddressToSwap, inputAddress, destinyChain } = + useContext(SwapContext); const showUserItems = async () => { const chainId = address === authenticatedUserAddress?.address ? chain?.id : ChainInfo[destinyChain].id; - - if (address && chainId && inputAddress) { + + if (address && chainId) { try { - const nftsList = await getNftsFrom(address, chainId, setNftsQueryStatus) + const nftsList = await getNftsFrom( + address, + chainId, + setNftsQueryStatus, + ); setNftsList(nftsList); - } catch (_) { - setNftsList([]); } } - } + }; useEffect(() => { - showUserItems() + showUserItems(); }, [address, chain, destinyChain]); useEffect(() => { if ( authenticatedUserAddress && address && - authenticatedUserAddress.equals(new EthereumAddress(address)) + authenticatedUserAddress.equals(new EthereumAddress(address)) && + variant === "their" ) { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); @@ -67,7 +71,7 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { }, [destinyChain]); useEffect(() => { - if (address !== authenticatedUserAddress?.address) { + if (address !== authenticatedUserAddress?.address && variant === "their") { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } @@ -75,8 +79,10 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { useEffect(() => { if ( - address !== authenticatedUserAddress?.address && - validatedAddressToSwap !== authenticatedUserAddress?.address || !inputAddress + authenticatedUserAddress && + address && + new EthereumAddress(address) && + variant === "their" ) { setNftsList([]); setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); @@ -84,7 +90,7 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { }, [inputAddress]); useEffect(() => { - if (!validatedAddressToSwap) { + if (!validatedAddressToSwap && variant === "their") { setNftsQueryStatus(NFTsQueryStatus.EMPTY_QUERY); } }, [validatedAddressToSwap]); @@ -93,7 +99,11 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => {
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? (
- +
) : nftsQueryStatus == NFTsQueryStatus.EMPTY_QUERY || !address ? (
@@ -132,4 +142,4 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { ) : null}
); -}; \ No newline at end of file +}; diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 7017fc79..17d62bc5 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -41,7 +41,10 @@ export const SwappingShelfs = () => {
- +
); From b3f24b91d0d126b00293b8676dadf8d7ae4cec97 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 21:17:30 -0300 Subject: [PATCH 168/305] update getNftsFrom fetch --- components/03-organisms/NftsShelf.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 70be1b75..6dfb220a 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -40,17 +40,13 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { : ChainInfo[destinyChain].id; if (address && chainId) { - try { - const nftsList = await getNftsFrom( - address, - chainId, - setNftsQueryStatus, - ); - - setNftsList(nftsList); - } catch (_) { - setNftsList([]); - } + getNftsFrom(address, chainId, setNftsQueryStatus) + .then((nftsList) => { + setNftsList(nftsList); + }) + .catch(() => { + setNftsList([]); + }); } }; From 2c2313148ef7fa72fce4f33585f0d40b5ab82524 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 21:32:07 -0300 Subject: [PATCH 169/305] update: merge develop --- components/02-molecules/OfferSummary.tsx | 34 +++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 9137ae37..171ed122 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -9,8 +9,13 @@ interface IOfferSummary { } export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { - const { validatedAddressToSwap, nftAuthUser, nftInputUser, inputAddress, userJustValidatedInput } = - useContext(SwapContext); + const { + validatedAddressToSwap, + nftAuthUser, + nftInputUser, + inputAddress, + userJustValidatedInput, + } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); const emptySquaresDefault = EmptyNftsCards(0, 4, 8, 12, 12); @@ -22,10 +27,8 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { 12, 12, ); - - const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; - + const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; return (
@@ -36,16 +39,17 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {

- { - forAuthedUser - ? "You give" - : !forAuthedUser && validatedAddressToSwap && inputAddress - ? `${userJustValidatedInput ? - new EthereumAddress(validatedAddressToSwap).getEllipsedAddress() + " gives" + {forAuthedUser + ? "You give" + : !forAuthedUser && validatedAddressToSwap && inputAddress + ? `${ + userJustValidatedInput + ? new EthereumAddress( + validatedAddressToSwap, + ).getEllipsedAddress() + " gives" : "Use the search bar!" - }` - : "Use the search bar!" - } + }` + : "Use the search bar!"}

@@ -60,7 +64,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {
{(forAuthedUser && !authenticatedUserAddress?.address) || - (!forAuthedUser && !validatedAddressToSwap) ? null : ( + (!forAuthedUser && !validatedAddressToSwap) ? null : ( <> {nftUser.map((nft, index) => ( Date: Tue, 27 Feb 2024 22:14:42 -0300 Subject: [PATCH 170/305] update: index & searchItemsShelf max-width --- components/01-atoms/SearchItemsShelf.tsx | 4 ++-- components/01-atoms/index.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/01-atoms/SearchItemsShelf.tsx b/components/01-atoms/SearchItemsShelf.tsx index 4af4144c..9d0ff9ff 100644 --- a/components/01-atoms/SearchItemsShelf.tsx +++ b/components/01-atoms/SearchItemsShelf.tsx @@ -1,4 +1,4 @@ -import { MagnifyingGlassIcon } from "@/components/01-atoms/icons/MagnifyingGlassIcon"; +import { MagnifyingGlassIcon } from "@/components/01-atoms"; import { useTheme } from "next-themes"; import cc from "classcat"; @@ -12,7 +12,7 @@ export const SearchItemsShelf = () => { name="search" type="search" className={cc([ - "flex items-center pl-9 rounded-lg h-8 gap-3 font-normal leading-5 text-sm not-italic placeholder-[#707572] border border-[#353836] opacity-80 bg-[#282B29] transition duration-300 ease-in-out focus:outline-none", + "flex items-center pl-9 rounded-lg max-w-[216px] h-8 gap-3 font-normal leading-5 text-sm not-italic placeholder-[#707572] border border-[#353836] opacity-80 bg-[#282B29] transition duration-300 ease-in-out focus:outline-none", theme == "light" ? "bg-[#F6F6F6] hover:bg-[#F0EEEE] border-[#E4E4E4] hover:border-[#D6D5D5] focus:border-[#AABE13] hover:shadow-[0_0_6px_1px_#00000014] focus:shadow-[0_0_6px_1px_#00000014] focus:border-opacity-100" : "hover:dark:bg-[#353836] hover:dark:border-[#505150] hover:dark:shadow-[0_0_6px_1px_#00000066] focus:dark:shadow-[0_0_6px_1px_#00000066] focus:dark:border-[#AABE13]", diff --git a/components/01-atoms/index.ts b/components/01-atoms/index.ts index 2cc92446..38df0a09 100644 --- a/components/01-atoms/index.ts +++ b/components/01-atoms/index.ts @@ -7,6 +7,7 @@ export * from "./OfferTag"; export * from "./NftsCardApprovedList"; export * from "./ProgressBar"; export * from "./SearchBar"; +export * from "./SearchItemsShelf"; export * from "./SelectAuthedUserChain"; export * from "./SelectDestinyChain"; export * from "./StatusOffers"; From f3cf12d58135a3d8456cad7abee1d44b7bec577b Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Tue, 27 Feb 2024 22:15:22 -0300 Subject: [PATCH 171/305] feat: add searchItemsShelf into SwapingShelfs --- components/01-atoms/Tab.tsx | 8 +++++--- components/03-organisms/SwappingShelfs.tsx | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/components/01-atoms/Tab.tsx b/components/01-atoms/Tab.tsx index 11fe780e..667caed0 100644 --- a/components/01-atoms/Tab.tsx +++ b/components/01-atoms/Tab.tsx @@ -30,7 +30,7 @@ export const Tab = ({ setActiveSwappingShelfID }: ITab) => { const [isActiveTab, setIsActiveTab] = useState(SwappingShelfID.THEIR_ITEMS); return ( -
+
{swappingTabs.map((tab) => { return (
{ isActiveTab == tab.id ? "dark:p-medium-bold-dark p-medium-bold border-b dark:border-[#DDF23D] border-black " : "dark:p-medium-bold p-medium-bold opacity-50 border-b dark:border-[#313131]", - "flex-1 p-4 cursor-pointer", + "flex cursor-pointer py-4 px-5", ])} role="tab" onClick={() => { @@ -47,7 +47,9 @@ export const Tab = ({ setActiveSwappingShelfID }: ITab) => { setIsActiveTab(tab.id); }} > -
{tab.name}
+
+ {tab.name} +
); })} diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 17d62bc5..ec634df9 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -1,6 +1,11 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { NftsShelf } from "@/components/03-organisms"; -import { SwapContext, SwappingShelfID, Tab } from "@/components/01-atoms/"; +import { + SwapContext, + SwappingShelfID, + SearchItemsShelf, + Tab, +} from "@/components/01-atoms/"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { useContext, useEffect, useState } from "react"; import { useNetwork } from "wagmi"; @@ -34,9 +39,18 @@ export const SwappingShelfs = () => { return (
- setActiveSwappingShelfID(input)} - /> +
+
+ + setActiveSwappingShelfID(input) + } + /> +
+
+ +
+
From 0098d9666401e9de8e35a5cbe04793988e68bc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Jos=C3=A9?= Date: Wed, 28 Feb 2024 00:12:07 -0300 Subject: [PATCH 172/305] fix/now gets correctly the ENS name from the searched address --- components/02-molecules/OfferSummary.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 2fced868..f2f1c0a2 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -37,10 +37,11 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { useEffect(()=>{ - if(!validatedAddressToSwap && !userJustValidatedInput) return - - const newAddress = new EthereumAddress(validatedAddressToSwap) - setSearchedEthereumAddress(newAddress); + if(validatedAddressToSwap && userJustValidatedInput && inputAddress){ + + const newAddress = new EthereumAddress(validatedAddressToSwap) + setSearchedEthereumAddress(newAddress); + } // eslint-disable-next-line react-hooks/exhaustive-deps },[validatedAddressToSwap]) @@ -50,7 +51,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {
- {!forAuthedUser && authenticatedUserAddress ? + {!forAuthedUser && authenticatedUserAddress && walletENSName ? : forAuthedUser && validatedAddressToSwap ? From a8e37672dd8aa04cd196f637479dcc759eda4aaf Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 01:46:02 -0300 Subject: [PATCH 173/305] fix: adjust the text to they get --- components/02-molecules/OfferSummary.tsx | 27 +++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index a6dcdf58..25836c00 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -45,10 +45,9 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { ensAddress: searchedEthereumAdress as unknown as EthereumAddress, }); - useEffect(()=>{ - if(validatedAddressToSwap && userJustValidatedInput && inputAddress){ - - const newAddress = new EthereumAddress(validatedAddressToSwap) + useEffect(() => { + if (validatedAddressToSwap && userJustValidatedInput && inputAddress) { + const newAddress = new EthereumAddress(validatedAddressToSwap); setSearchedEthereumAddress(newAddress); } @@ -60,11 +59,19 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => {
- {!forAuthedUser && authenticatedUserAddress && walletENSName ? - - : forAuthedUser && validatedAddressToSwap ? - - : } + {!forAuthedUser && authenticatedUserAddress && walletENSName ? ( + + ) : forAuthedUser && validatedAddressToSwap ? ( + + ) : ( + + )}

@@ -86,7 +93,7 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { validatedAddressToSwap, ).getEllipsedAddress()} gets` : (forAuthedUser && !validatedAddressToSwap) || !inputAddress - ? `Use the search bar` + ? `They get` : `Use the search bar`}

From 22c89d414a7a053db69be00b8c09998f91aa5282 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 13:52:25 -0300 Subject: [PATCH 174/305] update intial structure components --- components/01-atoms/SearchBar.tsx | 2 +- components/01-atoms/Tab.tsx | 4 ++-- components/02-molecules/NftCard.tsx | 2 +- components/02-molecules/NftsList.tsx | 6 +++--- components/03-organisms/NftsShelf.tsx | 4 ++-- components/03-organisms/SwappingShelfs.tsx | 24 ++++++++++++---------- components/04-templates/SwapSection.tsx | 19 +++++------------ styles/global.css | 2 +- 8 files changed, 28 insertions(+), 35 deletions(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index d6b0e051..ad75fb05 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -76,7 +76,7 @@ export const SearchBar = () => { }, [inputAddress]); return ( -
+

Who are you swapping with today? diff --git a/components/01-atoms/Tab.tsx b/components/01-atoms/Tab.tsx index 667caed0..a18dea35 100644 --- a/components/01-atoms/Tab.tsx +++ b/components/01-atoms/Tab.tsx @@ -30,7 +30,7 @@ export const Tab = ({ setActiveSwappingShelfID }: ITab) => { const [isActiveTab, setIsActiveTab] = useState(SwappingShelfID.THEIR_ITEMS); return ( -
+
{swappingTabs.map((tab) => { return (
{ className={cc([ isActiveTab == tab.id ? "dark:p-medium-bold-dark p-medium-bold border-b dark:border-[#DDF23D] border-black " - : "dark:p-medium-bold p-medium-bold opacity-50 border-b dark:border-[#313131]", + : "dark:p-medium-bold p-medium-bold opacity-50", "flex cursor-pointer py-4 px-5", ])} role="tab" diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index 535c5052..aec0d6fb 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -158,7 +158,7 @@ export const NftCard = ({ onError={handleImageLoadError} src={nftData.metadata?.image} alt={nftData.metadata?.name} - className="static z-10 w-full overflow-y-auto rounded-xl" + className="static z-10 w-full h-full overflow-y-auto rounded-xl" />, )} diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx index bbdae05e..51499325 100644 --- a/components/02-molecules/NftsList.tsx +++ b/components/02-molecules/NftsList.tsx @@ -22,7 +22,7 @@ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { const emptySquares = EmptyNftsCards(nftsList.length, 15, 24, 24, 24); const addTokenSquare = SwapAddTokenCard(); const nftSquares = nftsList.map((nft: NFT, index) => ( -
+
)); @@ -31,14 +31,14 @@ export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { emptySquares.pop(); // Removes the last element to fill with addToken const allSquares = [...nftSquares, ...emptySquares, addTokenSquare]; return ( -
+
{allSquares}
); } else { const allSquares = [...nftSquares, ...emptySquares]; return ( -
+
{allSquares}
); diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 66be84fc..3e3d538f 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -92,9 +92,9 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? ( -
+
{ }, [chain]); return ( -
-
+
+
@@ -47,18 +47,20 @@ export const SwappingShelfs = () => { } />
-
+
-
- -
-
- +
+
+ +
+
+ +
); diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 57722a59..323837e4 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -4,24 +4,15 @@ import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( - //
- // - //
- // - // - //
- // - //
- -
+
-
-
-
+
+
+
-
+
diff --git a/styles/global.css b/styles/global.css index c151975e..63711ca1 100644 --- a/styles/global.css +++ b/styles/global.css @@ -138,7 +138,7 @@ input:-webkit-autofill:focus { } .card-nft-normal { - @apply shadow-inner mx-auto w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; + @apply shadow-inner w-[90px] h-[90px] lg:w-[80px] lg:h-[80px] relative rounded-xl border border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; } .card-nft-small { @apply shadow-inner mx-auto w-[44px] h-[44px] lg:w-[44px] lg:h-[44px] relative rounded-xl border-2 border-[#E0E0E0] bg-[#E0E0E0] dark:bg-[#353836] dark:border-[#212322] flex flex-col shadow-token; From d85ad016921c61ba90656bcc3f5099765600ba62 Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 13:55:07 -0300 Subject: [PATCH 175/305] create chain hook --- components/04-templates/Layout.tsx | 29 +++++++++++++++++++- lib/client/contexts/ChainContext.tsx | 32 +++++++++++++++++++++++ lib/client/hooks/useAuthenticatedUser.tsx | 14 ++++++++-- lib/client/hooks/useConnectedChain.tsx | 23 ++++++++++++++++ lib/client/hooks/useWalletBalance.tsx | 11 ++++++-- 5 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 lib/client/contexts/ChainContext.tsx create mode 100644 lib/client/hooks/useConnectedChain.tsx diff --git a/components/04-templates/Layout.tsx b/components/04-templates/Layout.tsx index db81c87d..fcf0517d 100644 --- a/components/04-templates/Layout.tsx +++ b/components/04-templates/Layout.tsx @@ -1,9 +1,36 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { SidebarProvider } from "@/lib/client/contexts/SidebarContext.tsx"; import { useAuthedAccess } from "@/lib/client/hooks/useAuthedAccess"; +import { useConnectedChain } from "@/lib/client/hooks/useConnectedChain"; +import { sepolia, useSwitchNetwork } from "wagmi"; export const Layout = ({ children }: { children: React.ReactNode }) => { useAuthedAccess(); + const { isNetworkSupported } = useConnectedChain(); - return {children}; + const { switchNetwork } = useSwitchNetwork(); + + const changeChain = async () => { + try { + switchNetwork && (await switchNetwork(sepolia.id)); + } catch (switchError) { + console.error("Error switching network:", switchError); + } + }; + + return ( + + {!isNetworkSupported && ( +
+
+

Unsupported chain

+ +
+
+ )} + {children} +
+ ); }; diff --git a/lib/client/contexts/ChainContext.tsx b/lib/client/contexts/ChainContext.tsx new file mode 100644 index 00000000..99d4a440 --- /dev/null +++ b/lib/client/contexts/ChainContext.tsx @@ -0,0 +1,32 @@ +// import React, { createContext, useContext, useState, ReactNode, useCallback } from 'react'; +// // eslint-disable-next-line import/named +// import { Chain, mainnet } from 'viem/chains'; + +// interface ChainContextType { +// chain: Chain; +// changeChain: (chain: Chain) => void; // Update this line to match the function signature +// } + +// const SidebarContext = createContext(undefined); + +// export const ChainProvider = ({ children }: { children: ReactNode }) => { +// const [chain, setChain] = useState(mainnet); + +// const changeChain = useCallback((newChain: Chain) => { +// setChain(newChain); +// }, []); + +// return ( +// +// {children} +// +// ); +// }; + +// export const useConnectedChain = () => { +// const context = useContext(SidebarContext); +// if (context === undefined) { +// throw new Error('useConnectedChain must be used within a ChainProvider'); +// } +// return context; +// }; diff --git a/lib/client/hooks/useAuthenticatedUser.tsx b/lib/client/hooks/useAuthenticatedUser.tsx index 7f50b286..b2196860 100644 --- a/lib/client/hooks/useAuthenticatedUser.tsx +++ b/lib/client/hooks/useAuthenticatedUser.tsx @@ -10,6 +10,7 @@ interface AuthenticatedUserHook { loadingAuthenticatedUser: boolean; authenticatedUserEnsName: string | null; authenticatedUserAddress: EthereumAddress | null; + unsupportedChain: boolean; disconnectUser: () => void; } @@ -22,14 +23,22 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { useState(null); const [loadingAuthenticatedUser, setLoadingAuthenticatedUser] = useState(true); + const [isChainSupported, setisChainSupported] = useState(true); + + + console.log("nextAuthUser, address, isConnected :", nextAuthUser, address, isConnected) useEffect(() => { if ( typeof chain?.id === "number" && + // checks if network is supported !getRpcHttpUrlForNetwork.get(chain?.id) ) { - disconnect(); - return; + setisChainSupported(false) + // disconnect(); + // return; + } else { + setisChainSupported(true) } }, [chain]); @@ -85,6 +94,7 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { return { loadingEnsName: (loadingEnsName || !ensName) && !errorLoadingEnsName, + unsupportedChain: !isChainSupported, loadingAuthenticatedUser, authenticatedUserEnsName: loadingEnsName || errorLoadingEnsName || !ensName ? null : ensName, diff --git a/lib/client/hooks/useConnectedChain.tsx b/lib/client/hooks/useConnectedChain.tsx new file mode 100644 index 00000000..2a779390 --- /dev/null +++ b/lib/client/hooks/useConnectedChain.tsx @@ -0,0 +1,23 @@ +import { ChainInfo } from "../constants"; +import { useEffect, useState } from "react"; +import { useNetwork } from "wagmi"; + +export const useConnectedChain = () => { + const [isNetworkSupported, setIsNetworkSupported] = useState(true); + + const supportedNetworksId = Object.values(ChainInfo).map(net => net.id) + + const { chain } = useNetwork(); + + useEffect(() => { + if (chain && supportedNetworksId.includes(chain.id)) { + setIsNetworkSupported(true); + } else { + setIsNetworkSupported(false); + } + }, [chain, supportedNetworksId]); + + return { + isNetworkSupported, + }; +}; \ No newline at end of file diff --git a/lib/client/hooks/useWalletBalance.tsx b/lib/client/hooks/useWalletBalance.tsx index 2fb16526..fc493b04 100644 --- a/lib/client/hooks/useWalletBalance.tsx +++ b/lib/client/hooks/useWalletBalance.tsx @@ -1,5 +1,6 @@ +import { getRpcHttpUrlForNetwork } from "../constants"; import { EthereumAddress } from "@/lib/shared/types"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { createPublicClient, formatUnits, http } from "viem"; import { useNetwork } from "wagmi"; @@ -19,8 +20,10 @@ export const useWalletBalance = ({ walletAddress }: Props) => { const { chain } = useNetwork(); + const prevChainRef = useRef(chain); + useEffect(() => { - if (walletAddress && chain) { + if (walletAddress && chain && !!getRpcHttpUrlForNetwork.get(chain?.id)) { const client = createPublicClient({ chain: chain, transport: http(), @@ -44,8 +47,12 @@ export const useWalletBalance = ({ walletAddress }: Props) => { setBalance(null); setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); } + prevChainRef.current = chain; }, [walletAddress, chain]); + // console.log("Previous chain: ", prevChainRef.current); + // console.log("Current chain: ", chain); + return { balance, balanceQueryStatus, From 73ed8b98be66f7ef6a76556c62cc736c5d56509d Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 15:04:33 -0300 Subject: [PATCH 176/305] adjust NFTshelf height --- components/03-organisms/NftsShelf.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/03-organisms/NftsShelf.tsx b/components/03-organisms/NftsShelf.tsx index 3e3d538f..f9ad2f38 100644 --- a/components/03-organisms/NftsShelf.tsx +++ b/components/03-organisms/NftsShelf.tsx @@ -92,7 +92,7 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => { }, [validatedAddressToSwap]); return ( -
+
{nftsQueryStatus == NFTsQueryStatus.WITH_RESULTS && nftsList ? (
{
) : nftsQueryStatus == NFTsQueryStatus.NO_RESULTS ? ( -
+

Given address has no NFTs associated in the given network @@ -127,7 +127,7 @@ export const NftsShelf = ({ address, variant }: INftsShelfProps) => {

) : nftsQueryStatus == NFTsQueryStatus.LOADING ? ( -
+

Loading NFTs of{" "} From c5ddafe2c04e390f348aa0cf15831344295644dc Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 16:09:23 -0300 Subject: [PATCH 177/305] create snackbar remove button --- components/04-templates/Layout.tsx | 23 ------------------ lib/client/contexts/ChainContext.tsx | 32 -------------------------- lib/client/hooks/useConnectedChain.tsx | 11 +++++++-- 3 files changed, 9 insertions(+), 57 deletions(-) delete mode 100644 lib/client/contexts/ChainContext.tsx diff --git a/components/04-templates/Layout.tsx b/components/04-templates/Layout.tsx index fcf0517d..58ad1001 100644 --- a/components/04-templates/Layout.tsx +++ b/components/04-templates/Layout.tsx @@ -1,35 +1,12 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { SidebarProvider } from "@/lib/client/contexts/SidebarContext.tsx"; import { useAuthedAccess } from "@/lib/client/hooks/useAuthedAccess"; -import { useConnectedChain } from "@/lib/client/hooks/useConnectedChain"; -import { sepolia, useSwitchNetwork } from "wagmi"; export const Layout = ({ children }: { children: React.ReactNode }) => { useAuthedAccess(); - const { isNetworkSupported } = useConnectedChain(); - - const { switchNetwork } = useSwitchNetwork(); - - const changeChain = async () => { - try { - switchNetwork && (await switchNetwork(sepolia.id)); - } catch (switchError) { - console.error("Error switching network:", switchError); - } - }; return ( - {!isNetworkSupported && ( -

-
-

Unsupported chain

- -
-
- )} {children} ); diff --git a/lib/client/contexts/ChainContext.tsx b/lib/client/contexts/ChainContext.tsx deleted file mode 100644 index 99d4a440..00000000 --- a/lib/client/contexts/ChainContext.tsx +++ /dev/null @@ -1,32 +0,0 @@ -// import React, { createContext, useContext, useState, ReactNode, useCallback } from 'react'; -// // eslint-disable-next-line import/named -// import { Chain, mainnet } from 'viem/chains'; - -// interface ChainContextType { -// chain: Chain; -// changeChain: (chain: Chain) => void; // Update this line to match the function signature -// } - -// const SidebarContext = createContext(undefined); - -// export const ChainProvider = ({ children }: { children: ReactNode }) => { -// const [chain, setChain] = useState(mainnet); - -// const changeChain = useCallback((newChain: Chain) => { -// setChain(newChain); -// }, []); - -// return ( -// -// {children} -// -// ); -// }; - -// export const useConnectedChain = () => { -// const context = useContext(SidebarContext); -// if (context === undefined) { -// throw new Error('useConnectedChain must be used within a ChainProvider'); -// } -// return context; -// }; diff --git a/lib/client/hooks/useConnectedChain.tsx b/lib/client/hooks/useConnectedChain.tsx index 2a779390..a6f14768 100644 --- a/lib/client/hooks/useConnectedChain.tsx +++ b/lib/client/hooks/useConnectedChain.tsx @@ -1,6 +1,7 @@ import { ChainInfo } from "../constants"; import { useEffect, useState } from "react"; -import { useNetwork } from "wagmi"; +import toast from "react-hot-toast"; +import { sepolia, useNetwork, useSwitchNetwork } from "wagmi"; export const useConnectedChain = () => { const [isNetworkSupported, setIsNetworkSupported] = useState(true); @@ -9,13 +10,19 @@ export const useConnectedChain = () => { const { chain } = useNetwork(); + const { switchNetwork } = useSwitchNetwork(); + useEffect(() => { if (chain && supportedNetworksId.includes(chain.id)) { setIsNetworkSupported(true); } else { setIsNetworkSupported(false); + toast.error(`Network not supported, change network and try again`, { + id: "welcome-toast", + }); + switchNetwork && switchNetwork(sepolia.id) } - }, [chain, supportedNetworksId]); + }, [chain, supportedNetworksId, switchNetwork]); return { isNetworkSupported, From c3386e8f07312e11813cbf34b5546edd94dcb63b Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 16:13:56 -0300 Subject: [PATCH 178/305] remove unused code --- lib/client/hooks/useAuthenticatedUser.tsx | 6 ------ lib/client/hooks/useWalletBalance.tsx | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/client/hooks/useAuthenticatedUser.tsx b/lib/client/hooks/useAuthenticatedUser.tsx index b2196860..9e21ec48 100644 --- a/lib/client/hooks/useAuthenticatedUser.tsx +++ b/lib/client/hooks/useAuthenticatedUser.tsx @@ -10,7 +10,6 @@ interface AuthenticatedUserHook { loadingAuthenticatedUser: boolean; authenticatedUserEnsName: string | null; authenticatedUserAddress: EthereumAddress | null; - unsupportedChain: boolean; disconnectUser: () => void; } @@ -23,7 +22,6 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { useState(null); const [loadingAuthenticatedUser, setLoadingAuthenticatedUser] = useState(true); - const [isChainSupported, setisChainSupported] = useState(true); console.log("nextAuthUser, address, isConnected :", nextAuthUser, address, isConnected) @@ -34,11 +32,8 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { // checks if network is supported !getRpcHttpUrlForNetwork.get(chain?.id) ) { - setisChainSupported(false) // disconnect(); // return; - } else { - setisChainSupported(true) } }, [chain]); @@ -94,7 +89,6 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { return { loadingEnsName: (loadingEnsName || !ensName) && !errorLoadingEnsName, - unsupportedChain: !isChainSupported, loadingAuthenticatedUser, authenticatedUserEnsName: loadingEnsName || errorLoadingEnsName || !ensName ? null : ensName, diff --git a/lib/client/hooks/useWalletBalance.tsx b/lib/client/hooks/useWalletBalance.tsx index fc493b04..85737c19 100644 --- a/lib/client/hooks/useWalletBalance.tsx +++ b/lib/client/hooks/useWalletBalance.tsx @@ -1,6 +1,6 @@ import { getRpcHttpUrlForNetwork } from "../constants"; import { EthereumAddress } from "@/lib/shared/types"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { createPublicClient, formatUnits, http } from "viem"; import { useNetwork } from "wagmi"; @@ -20,8 +20,6 @@ export const useWalletBalance = ({ walletAddress }: Props) => { const { chain } = useNetwork(); - const prevChainRef = useRef(chain); - useEffect(() => { if (walletAddress && chain && !!getRpcHttpUrlForNetwork.get(chain?.id)) { const client = createPublicClient({ @@ -47,12 +45,8 @@ export const useWalletBalance = ({ walletAddress }: Props) => { setBalance(null); setBalanceQueryStatus(WalletBalanceQueryStatus.ERROR); } - prevChainRef.current = chain; }, [walletAddress, chain]); - // console.log("Previous chain: ", prevChainRef.current); - // console.log("Current chain: ", chain); - return { balance, balanceQueryStatus, From a04aa0660785a276f6abf7479061688a830e5a0d Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 16:14:48 -0300 Subject: [PATCH 179/305] remove console logs --- lib/client/hooks/useAuthenticatedUser.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/client/hooks/useAuthenticatedUser.tsx b/lib/client/hooks/useAuthenticatedUser.tsx index 9e21ec48..fc2ef076 100644 --- a/lib/client/hooks/useAuthenticatedUser.tsx +++ b/lib/client/hooks/useAuthenticatedUser.tsx @@ -23,9 +23,6 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { const [loadingAuthenticatedUser, setLoadingAuthenticatedUser] = useState(true); - - console.log("nextAuthUser, address, isConnected :", nextAuthUser, address, isConnected) - useEffect(() => { if ( typeof chain?.id === "number" && From 64c1482d7332151340bb724c95bbd887d7ebf931 Mon Sep 17 00:00:00 2001 From: eduramme Date: Wed, 28 Feb 2024 16:17:40 -0300 Subject: [PATCH 180/305] use connectedChain hook inside Layout component --- components/04-templates/Layout.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/04-templates/Layout.tsx b/components/04-templates/Layout.tsx index 58ad1001..75dfdfdb 100644 --- a/components/04-templates/Layout.tsx +++ b/components/04-templates/Layout.tsx @@ -1,9 +1,11 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { SidebarProvider } from "@/lib/client/contexts/SidebarContext.tsx"; import { useAuthedAccess } from "@/lib/client/hooks/useAuthedAccess"; +import { useConnectedChain } from "@/lib/client/hooks/useConnectedChain"; export const Layout = ({ children }: { children: React.ReactNode }) => { useAuthedAccess(); + useConnectedChain(); return ( From 3469f942197f3e41e9947c06344a4dbb6829cf4b Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 16:56:38 -0300 Subject: [PATCH 181/305] fix: style css --- components/01-atoms/Tab.tsx | 4 +--- components/03-organisms/SwappingShelfs.tsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/01-atoms/Tab.tsx b/components/01-atoms/Tab.tsx index a18dea35..0750b01d 100644 --- a/components/01-atoms/Tab.tsx +++ b/components/01-atoms/Tab.tsx @@ -47,9 +47,7 @@ export const Tab = ({ setActiveSwappingShelfID }: ITab) => { setIsActiveTab(tab.id); }} > -
- {tab.name} -
+
{tab.name}
); })} diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 65b9171b..6711c729 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -51,7 +51,7 @@ export const SwappingShelfs = () => {
-
+
From d863720d59c2f29a2d3584c4e18c13242235afcb Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 20:06:03 -0300 Subject: [PATCH 182/305] refactor: remove 95% from search-bar --- components/01-atoms/SearchBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index ad75fb05..a8ee133d 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -76,7 +76,7 @@ export const SearchBar = () => { }, [inputAddress]); return ( -
+

Who are you swapping with today? From b7d6ff330d9af52cea26dc84312912dd3034249e Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 20:07:05 -0300 Subject: [PATCH 183/305] feat: add shadow in swapStation * add swapIcon with adjustments in style --- components/03-organisms/SwapStation.tsx | 32 +++++++++++++------------ styles/global.css | 6 ++++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/components/03-organisms/SwapStation.tsx b/components/03-organisms/SwapStation.tsx index 52d19306..663ad68e 100644 --- a/components/03-organisms/SwapStation.tsx +++ b/components/03-organisms/SwapStation.tsx @@ -1,4 +1,9 @@ -import { PaperPlane, SwapContext, SwapExpireTime } from "@/components/01-atoms"; +import { + PaperPlane, + SwapContext, + SwapExpireTime, + SwapIcon, +} from "@/components/01-atoms"; import { ConfirmSwapModal, OfferSummary } from "@/components/02-molecules"; import { useContext, useEffect, useState } from "react"; import cc from "classcat"; @@ -43,24 +48,21 @@ export const SwapStation = () => { }; return ( -
-
-
-
-

- Swap offer -

-
-
- -
+
+
+
+

+ Swap offer +

+
-
+
+
+ +
-
-
Date: Wed, 28 Feb 2024 20:07:49 -0300 Subject: [PATCH 184/305] update: styletype in emptyNftsCard to render an empty with ajusted size --- components/01-atoms/EmptyNftsCards.tsx | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/components/01-atoms/EmptyNftsCards.tsx b/components/01-atoms/EmptyNftsCards.tsx index cb67f5ef..0ff01c8c 100644 --- a/components/01-atoms/EmptyNftsCards.tsx +++ b/components/01-atoms/EmptyNftsCards.tsx @@ -1,4 +1,6 @@ +import { NftSizeClassNames, StyleVariant } from "../02-molecules"; import { useScreenSize } from "@/lib/client/hooks/useScreenSize"; +import cc from "classcat"; export const EmptyNftsCards = ( tokenArrayLength: number, @@ -6,6 +8,7 @@ export const EmptyNftsCards = ( isWideScreenTotalSquares: number, isDesktopTotalSquares: number, isTabletTotalSquares: number, + styleType?: StyleVariant, ) => { const { isDesktop, isTablet, isWideScreen, isMobile } = useScreenSize(); @@ -15,13 +18,18 @@ export const EmptyNftsCards = ( // We are getting X count as the LCM to fill the rows with empty cards correctly. isMobile ? ((totalSquares = ismobileTotalSquares), - ismobileTotalSquares == 4 ? (totalSquaresX = 4) : (totalSquaresX = 3)) + ismobileTotalSquares == 5 ? (totalSquaresX = 5) : (totalSquaresX = 3)) : isWideScreen ? ((totalSquares = isWideScreenTotalSquares), - isWideScreenTotalSquares == 8 ? (totalSquaresX = 4) : (totalSquaresX = 6)) + isWideScreenTotalSquares == 10 + ? (totalSquaresX = 5) + : (totalSquaresX = 6)) : isDesktop - ? ((totalSquares = isDesktopTotalSquares), (totalSquaresX = 6)) - : isTablet && ((totalSquares = isTabletTotalSquares), (totalSquaresX = 6)); + ? ((totalSquares = isDesktopTotalSquares), + isDesktopTotalSquares == 8 ? (totalSquaresX = 4) : (totalSquaresX = 6)) + : isTablet && + ((totalSquares = isTabletTotalSquares), + isTabletTotalSquares == 10 ? (totalSquaresX = 5) : (totalSquaresX = 6)); const spareTokensX = tokenArrayLength % totalSquaresX; const emptySquaresCountX = spareTokensX ? totalSquaresX - spareTokensX : 0; @@ -34,7 +42,14 @@ export const EmptyNftsCards = ( const emptySquares = Array.from({ length: emptySquaresCount }, (_, index) => ( <> -
+
)); From 4da4e12ace938164cc3ace38798672ec0688b103 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 20:08:17 -0300 Subject: [PATCH 185/305] update: export styleVariant from nftCard --- components/02-molecules/NftCard.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/02-molecules/NftCard.tsx b/components/02-molecules/NftCard.tsx index aec0d6fb..83a735c3 100644 --- a/components/02-molecules/NftCard.tsx +++ b/components/02-molecules/NftCard.tsx @@ -37,9 +37,14 @@ export enum NftCardStyleType { LARGE = "large", } -type StyleVariant = NftCardStyleType | "small" | "normal" | "medium" | "large"; - -const NftSizeClassNames = { +export type StyleVariant = + | NftCardStyleType + | "small" + | "normal" + | "medium" + | "large"; + +export const NftSizeClassNames = { [NftCardStyleType.SMALL]: "card-nft-small", [NftCardStyleType.NORMAL]: "card-nft-normal", [NftCardStyleType.MEDIUM]: "card-nft-medium", From fd233e94721747e4164f382307baca9cd4cc2e22 Mon Sep 17 00:00:00 2001 From: heronlancellot Date: Wed, 28 Feb 2024 20:11:36 -0300 Subject: [PATCH 186/305] feat: add new style in dApp in all devices --- components/02-molecules/OfferSummary.tsx | 125 ++++++++++++----------- components/04-templates/SwapSection.tsx | 10 +- 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/components/02-molecules/OfferSummary.tsx b/components/02-molecules/OfferSummary.tsx index 171ed122..9ca34111 100644 --- a/components/02-molecules/OfferSummary.tsx +++ b/components/02-molecules/OfferSummary.tsx @@ -18,76 +18,87 @@ export const OfferSummary = ({ forAuthedUser }: IOfferSummary) => { } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); - const emptySquaresDefault = EmptyNftsCards(0, 4, 8, 12, 12); - const emptySquaresAuthUser = EmptyNftsCards(nftAuthUser.length, 4, 8, 12, 12); + const emptySquaresDefault = EmptyNftsCards(0, 6, 10, 8, 12, "medium"); + const emptySquaresAuthUser = EmptyNftsCards( + nftAuthUser.length, + 6, + 10, + 8, + 12, + "medium", + ); const emptySquaresInputUser = EmptyNftsCards( nftInputUser.length, - 4, + 6, + 10, 8, 12, - 12, + "medium", ); const nftUser = forAuthedUser ? nftAuthUser : nftInputUser; return ( -
-
-
-
- -
-
-

- {forAuthedUser - ? "You give" - : !forAuthedUser && validatedAddressToSwap && inputAddress - ? `${ - userJustValidatedInput - ? new EthereumAddress( - validatedAddressToSwap, - ).getEllipsedAddress() + " gives" - : "Use the search bar!" - }` - : "Use the search bar!"} -

+
+
+
+
+
+ +
+
+

+ {forAuthedUser + ? "You give" + : !forAuthedUser && validatedAddressToSwap && inputAddress + ? `${ + userJustValidatedInput + ? new EthereumAddress( + validatedAddressToSwap, + ).getEllipsedAddress() + " gives" + : "Use the search bar!" + }` + : "Use the search bar!"} +

+
+ {!forAuthedUser && !validatedAddressToSwap ? null : ( +
+ {nftUser.length} item + {nftUser.length !== 1 ? "s" : ""} +
+ )}
- {!forAuthedUser && !validatedAddressToSwap ? null : ( -
- {nftUser.length} item - {nftUser.length !== 1 ? "s" : ""} -
- )} -
-
-
- {(forAuthedUser && !authenticatedUserAddress?.address) || - (!forAuthedUser && !validatedAddressToSwap) ? null : ( - <> - {nftUser.map((nft, index) => ( - - ))} - - )} +
+
+ {(forAuthedUser && !authenticatedUserAddress?.address) || + (!forAuthedUser && !validatedAddressToSwap) ? null : ( + <> + {nftUser.map((nft, index) => ( + + ))} + + )} - {forAuthedUser - ? emptySquaresAuthUser - : !forAuthedUser - ? emptySquaresInputUser - : emptySquaresDefault} + {forAuthedUser + ? emptySquaresAuthUser + : !forAuthedUser + ? emptySquaresInputUser + : emptySquaresDefault} +
diff --git a/components/04-templates/SwapSection.tsx b/components/04-templates/SwapSection.tsx index 323837e4..ea666cc9 100644 --- a/components/04-templates/SwapSection.tsx +++ b/components/04-templates/SwapSection.tsx @@ -4,15 +4,15 @@ import { SwapStation, SwappingShelfs } from "@/components/03-organisms"; export const SwapSection = () => { return ( -
+
-
-
-
+
+
+
-
+
From b2a35b806d15c0e1eb3734963d997b5b7dd9f624 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Wed, 28 Feb 2024 20:27:45 -0300 Subject: [PATCH 187/305] feat: Improving TS functions with blockchain calls --- .env.example | 4 +- components/01-atoms/ApprovedTokenCards.tsx | 140 ++++++++++-------- components/01-atoms/SwapContext.tsx | 133 +++++++++-------- components/01-atoms/SwapExpireTime.tsx | 6 +- components/01-atoms/SwapModalButton.tsx | 8 +- components/01-atoms/SwapModalLayout.tsx | 8 +- components/02-molecules/ConfirmSwapModal.tsx | 33 ++--- components/02-molecules/ProgressStatus.tsx | 30 +--- components/02-molecules/TokenCard.tsx | 24 ++- components/03-organisms/SwappingShelfs.tsx | 4 +- components/03-organisms/TokensShelf.tsx | 3 +- lib/client/abi.ts | 6 +- ...blockchain-data.ts => blockchain-utils.ts} | 108 +++++++++----- lib/client/constants.ts | 24 ++- lib/client/hooks/subgraphQueries.ts | 6 +- lib/client/hooks/useAuthenticatedUser.tsx | 7 +- lib/client/swap-utils.ts | 12 +- lib/service/approveSwap.ts | 60 +++++--- lib/service/createSwap.ts | 13 +- lib/service/verifyTokensSwapApproval.ts | 52 +++++-- lib/wallet/wallet-config.ts | 10 +- 21 files changed, 393 insertions(+), 298 deletions(-) rename lib/client/{blockchain-data.ts => blockchain-utils.ts} (73%) diff --git a/.env.example b/.env.example index ba56e297..4ae24676 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,7 @@ NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=50db9e195634356bb8ab0375a9f07607 -NEXT_PUBLIC_ALCHEMY_SEPOLIA_HTTP= +NEXT_PUBLIC_ALCHEMY_ETHEREUM_KEY= NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY= -NEXT_PUBLIC_ALCHEMY_MUMBAI_HTTP= NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY= -NEXT_PUBLIC_ALCHEMY_ETHEREUM_HTTP= # Subgraph endpoint production query diff --git a/components/01-atoms/ApprovedTokenCards.tsx b/components/01-atoms/ApprovedTokenCards.tsx index 662016e1..98328981 100644 --- a/components/01-atoms/ApprovedTokenCards.tsx +++ b/components/01-atoms/ApprovedTokenCards.tsx @@ -1,106 +1,113 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { - ADDRESS_ZERO, - SWAPLACE_SMART_CONTRACT_ADDRESS, -} from "@/lib/client/constants"; +import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants"; import { SwapContext } from "@/components/01-atoms"; -import { - TokenCard, - NftCardActionType, - NftCardStyleType, -} from "@/components/02-molecules"; +import { TokenCard, NftCardStyleType } from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { approveTokensBeforeSwap } from "@/lib/client/swap-utils"; -import { IApproveSwap } from "@/lib/client/blockchain-data"; +import { + IApproveTokenSwap, + getTokenAmountOrId, +} from "@/lib/client/blockchain-utils"; import { approveSwap } from "@/lib/service/approveSwap"; +import { isTokenSwapApproved } from "@/lib/service/verifyTokensSwapApproval"; import { getTokenName } from "@/lib/client/tokens"; import { Token } from "@/lib/shared/types"; import cc from "classcat"; -import { useContext, useEffect } from "react"; +import { useContext, useEffect, useState } from "react"; import toast from "react-hot-toast"; -import { useNetwork, useWalletClient } from "wagmi"; +import { type WalletClient, useNetwork, useWalletClient } from "wagmi"; +import { type TransactionReceipt } from "viem"; export const ApprovedTokenCards = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); const { chain } = useNetwork(); const { data: walletClient } = useWalletClient(); + const [tokensBeingApproved, setTokensBeingApproved] = useState([]); + const [tokensApprovedForSwap, setTokensApprovedForSwap] = useState( + [], + ); const { authenticatedUserTokensList, - authedUserSelectedNftsApprovalStatus, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, - allSelectedNftsApproved, + setApprovedTokensCount, + approvedTokensCount, } = useContext(SwapContext); useEffect(() => { - const fetchApprove = async () => { - await approveTokensBeforeSwap( - authenticatedUserTokensList, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, - ); - }; - fetchApprove(); - }, [authenticatedUserTokensList, allSelectedNftsApproved]); + setApprovedTokensCount(0); + }, [authenticatedUserTokensList]); if (!authenticatedUserAddress?.address) { return null; } + let chainId: number; - const handleApprove = async (token: Token) => { - if (typeof chain?.id != "undefined") { - chainId = chain?.id; + + const handleApprove = async ( + token: Token, + loadingCallback: (token: Token) => void, + ): Promise => { + if (!chain?.id || !walletClient) { + throw new Error("User's wallet is not connected"); } - const swapData: IApproveSwap = { - walletClient: walletClient, + if (!token.contract) + throw new Error(`Token contract is not defined for: ${token}`); + + const swapData: IApproveTokenSwap = { + walletClient: walletClient as WalletClient, spender: SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as `0x${string}`, - tokenContractAddress: token.contract, - amountOrId: BigInt(token?.id as string), + tokenContractAddress: token.contract as `0x${string}`, + amountOrId: getTokenAmountOrId(token), + chainId: chain.id, + token, + onConfirm: loadingCallback, }; try { const transactionReceipt = await approveSwap(swapData); + if (transactionReceipt != undefined) { - toast.success("Approval successfully"); + toast.success("Approved successfully"); + setTokensApprovedForSwap([...tokensApprovedForSwap, token]); return transactionReceipt; } else { - toast.error("Approval Failed"); + toast.error("Approval failed"); } } catch (error) { - toast.error("Approval Rejected"); + // TODO: map error scenarios and create corresponding error triggers + toast.error("Approval rejected"); console.error(error); } }; - const validateApprovalTokens = (arraynftApproval: any[]) => { - const isValidApproved = !arraynftApproval.some((token) => { - return token.approved != SWAPLACE_SMART_CONTRACT_ADDRESS[chainId]; - }); - - setAllSelectedNftsAreApproved(isValidApproved); + const addTokenToLoadingState = (token: Token) => { + setTokensBeingApproved([...tokensBeingApproved, token]); }; - const approveNftForSwapping = async (token: Token, index: number) => { + const handleTokenApproval = async (token: Token) => { if (typeof chain?.id != "undefined") { chainId = chain?.id; - } - if ( - authedUserSelectedNftsApprovalStatus[index]?.approved === - SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] - ) { - toast.error("Token already approved."); } else { - await handleApprove(token).then((result) => { - if (result != undefined) { - const nftWasApproved = (authedUserSelectedNftsApprovalStatus[ - index - ].approved = SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as any); + throw new Error("User is not connected to any network"); + } - setAuthedUserNftsApprovalStatus([nftWasApproved]); + const isApproved = await isTokenSwapApproved({ + token, + chainId, + }); + + if (isApproved) { + setTokensApprovedForSwap([...tokensApprovedForSwap, token]); + toast.success("Token approved."); + } else { + await handleApprove(token, addTokenToLoadingState).then((isApproved) => { + if (typeof isApproved !== "undefined") { + setApprovedTokensCount(approvedTokensCount + 1); } - validateApprovalTokens(authedUserSelectedNftsApprovalStatus); + + setTokensBeingApproved( + tokensBeingApproved.filter((tk) => tk === token), + ); }); } }; @@ -113,18 +120,19 @@ export const ApprovedTokenCards = () => { key={index} className={cc([ "flex p-4 items-center gap-4 h-[68px]", - authedUserSelectedNftsApprovalStatus[index]?.approved === - ADDRESS_ZERO + !tokensApprovedForSwap.includes(token) ? "bg-[#353836] rounded-xl" : "dark:bg-[#DDF23D] bg-[#97a529] rounded-xl disabled cursor-not-allowed", + { + "disabled cursor-wait": tokensBeingApproved.includes(token), + }, ])} role="button" - onClick={() => approveNftForSwapping(token, index)} + onClick={() => handleTokenApproval(token)} >
{
- {authedUserSelectedNftsApprovalStatus[index]?.approved === - ADDRESS_ZERO ? ( + {!tokensApprovedForSwap.includes(token) ? (

{getTokenName(authenticatedUserTokensList[index])}

@@ -144,10 +151,13 @@ export const ApprovedTokenCards = () => { )}
- {authedUserSelectedNftsApprovalStatus[index]?.approved === - ADDRESS_ZERO ? ( + {tokensBeingApproved.includes(token) ? ( +

+ WAITING BLOCKCHAIN CONFIRMATION +

+ ) : !tokensApprovedForSwap.includes(token) ? (

- PENDING APPROVAL + CLICK TO APPROVE

) : (
diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index d3f51b53..72c42d43 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -6,71 +6,57 @@ import { ADDRESS_ZERO, SupportedNetworks } from "@/lib/client/constants"; import { EthereumAddress, Token } from "@/lib/shared/types"; import { ButtonClickPossibilities, - IArrayStatusTokenApproved, + TokenApprovalData, SwapModalSteps, -} from "@/lib/client/blockchain-data"; +} from "@/lib/client/blockchain-utils"; import React, { Dispatch, useEffect, useState } from "react"; import toast from "react-hot-toast"; interface SwapContextProps { + // Application universal need + destinyChain: SupportedNetworks; + setDestinyChain: Dispatch>; + + // Searched user related inputAddress: string; - validatedAddressToSwap: string; setInputAddress: (address: string) => void; + validatedAddressToSwap: string; + validateAddressToSwap: ( authedUser: EthereumAddress, inputEnsAddress: string | null | undefined, ) => void; - setUserJustValidatedInput: Dispatch>; + searchedUserTokensList: Token[]; + setSearchedUserTokensList: Dispatch>; + /* + Below state is used for Ui rules only, setting new stylings + if the Search bar content was just now submitted + */ userJustValidatedInput: boolean; - setAuthenticatedUsedTokensList: Dispatch>; + setUserJustValidatedInput: Dispatch>; + + // Authed user related + authedUserSelectedTokensApprovalStatus: TokenApprovalData[]; authenticatedUserTokensList: Token[]; - setSearchedUserTokensList: Dispatch>; - searchedUserTokensList: Token[]; - destinyChain: SupportedNetworks; - setDestinyChain: Dispatch>; - setTimeDate: Dispatch>; - timeDate: bigint; - setAllSelectedNftsAreApproved: Dispatch>; - allSelectedNftsApproved: boolean; - setAuthedUserNftsApprovalStatus: Dispatch< - React.SetStateAction + setAuthenticatedUserTokensList: Dispatch>; + approvedTokensCount: number; + setApprovedTokensCount: Dispatch>; + setAuthedUserTokensApprovalStatus: Dispatch< + React.SetStateAction >; - authedUserSelectedNftsApprovalStatus: IArrayStatusTokenApproved[]; - updateSwapStep: (buttonClickAction: ButtonClickPossibilities) => void; + + // Swap modal related currentSwapModalStep: SwapModalSteps; + updateSwapStep: (buttonClickAction: ButtonClickPossibilities) => void; + timeDate: bigint; + setTimeDate: Dispatch>; } -export const SwapContext = React.createContext({ - inputAddress: "", - validatedAddressToSwap: "", - validateAddressToSwap: ( - _authedUser: EthereumAddress, - _inputEnsAddress: string | null | undefined, - ) => {}, - setInputAddress: (address: string) => {}, - setUserJustValidatedInput: () => {}, - userJustValidatedInput: false, - setAuthenticatedUsedTokensList: () => {}, - authenticatedUserTokensList: [], - setSearchedUserTokensList: () => {}, - searchedUserTokensList: [], - destinyChain: SupportedNetworks.SEPOLIA, - setDestinyChain: () => {}, - setTimeDate: () => {}, - timeDate: BigInt(1), - setAllSelectedNftsAreApproved: () => {}, - allSelectedNftsApproved: false, - setAuthedUserNftsApprovalStatus: () => {}, - authedUserSelectedNftsApprovalStatus: [], - currentSwapModalStep: SwapModalSteps.APPROVE_TOKENS, - updateSwapStep: (buttonClickAction: ButtonClickPossibilities) => {}, -}); - export const SwapContextProvider = ({ children }: any) => { const [inputAddress, setInputAddress] = useState(""); const [validatedAddressToSwap, setValidatedAddressToSwap] = useState(""); const [userJustValidatedInput, setUserJustValidatedInput] = useState(true); - const [authenticatedUserTokensList, setAuthenticatedUsedTokensList] = + const [authenticatedUserTokensList, setAuthenticatedUserTokensList] = useState([]); const [searchedUserTokensList, setSearchedUserTokensList] = useState( [], @@ -82,12 +68,11 @@ export const SwapContextProvider = ({ children }: any) => { const [currentSwapModalStep, setCurrentSwapModalStep] = useState(SwapModalSteps.APPROVE_TOKENS); - const [allSelectedNftsApproved, setAllSelectedNftsAreApproved] = - useState(false); + const [approvedTokensCount, setApprovedTokensCount] = useState(0); const [ - authedUserSelectedNftsApprovalStatus, - setAuthedUserNftsApprovalStatus, - ] = useState([]); + authedUserSelectedTokensApprovalStatus, + setAuthedUserTokensApprovalStatus, + ] = useState([]); const validateAddressToSwap = ( _authedUser: EthereumAddress, @@ -184,7 +169,7 @@ export const SwapContextProvider = ({ children }: any) => { validateAddressToSwap, setUserJustValidatedInput, userJustValidatedInput, - setAuthenticatedUsedTokensList, + setAuthenticatedUserTokensList, authenticatedUserTokensList, setSearchedUserTokensList, searchedUserTokensList, @@ -192,10 +177,10 @@ export const SwapContextProvider = ({ children }: any) => { setDestinyChain, setTimeDate, timeDate, - setAllSelectedNftsAreApproved, - allSelectedNftsApproved, - setAuthedUserNftsApprovalStatus, - authedUserSelectedNftsApprovalStatus, + approvedTokensCount, + setApprovedTokensCount, + setAuthedUserTokensApprovalStatus, + authedUserSelectedTokensApprovalStatus, updateSwapStep, currentSwapModalStep, }); @@ -207,8 +192,8 @@ export const SwapContextProvider = ({ children }: any) => { searchedUserTokensList, destinyChain, timeDate, - allSelectedNftsApproved, - authedUserSelectedNftsApprovalStatus, + approvedTokensCount, + authedUserSelectedTokensApprovalStatus, currentSwapModalStep, ]); @@ -219,7 +204,7 @@ export const SwapContextProvider = ({ children }: any) => { validateAddressToSwap, setUserJustValidatedInput, userJustValidatedInput, - setAuthenticatedUsedTokensList, + setAuthenticatedUserTokensList, authenticatedUserTokensList, setSearchedUserTokensList, searchedUserTokensList, @@ -227,10 +212,10 @@ export const SwapContextProvider = ({ children }: any) => { setDestinyChain, setTimeDate, timeDate, - setAllSelectedNftsAreApproved, - allSelectedNftsApproved, - setAuthedUserNftsApprovalStatus, - authedUserSelectedNftsApprovalStatus, + approvedTokensCount, + setApprovedTokensCount, + setAuthedUserTokensApprovalStatus, + authedUserSelectedTokensApprovalStatus, updateSwapStep, currentSwapModalStep, }); @@ -239,3 +224,29 @@ export const SwapContextProvider = ({ children }: any) => { {children} ); }; + +export const SwapContext = React.createContext({ + inputAddress: "", + validatedAddressToSwap: "", + validateAddressToSwap: ( + _authedUser: EthereumAddress, + _inputEnsAddress: string | null | undefined, + ) => {}, + setInputAddress: (address: string) => {}, + setUserJustValidatedInput: () => {}, + userJustValidatedInput: false, + setAuthenticatedUserTokensList: () => {}, + authenticatedUserTokensList: [], + setSearchedUserTokensList: () => {}, + searchedUserTokensList: [], + destinyChain: SupportedNetworks.SEPOLIA, + setDestinyChain: () => {}, + timeDate: BigInt(1), + setTimeDate: () => {}, + approvedTokensCount: 0, + setApprovedTokensCount: () => {}, + setAuthedUserTokensApprovalStatus: () => {}, + authedUserSelectedTokensApprovalStatus: [], + currentSwapModalStep: SwapModalSteps.APPROVE_TOKENS, + updateSwapStep: (buttonClickAction: ButtonClickPossibilities) => {}, +}); diff --git a/components/01-atoms/SwapExpireTime.tsx b/components/01-atoms/SwapExpireTime.tsx index 467901b6..10b794f0 100644 --- a/components/01-atoms/SwapExpireTime.tsx +++ b/components/01-atoms/SwapExpireTime.tsx @@ -12,16 +12,16 @@ export const SwapExpireTime = () => { TimeStampDate.ONE_DAY, ); - let chainID: number; + let chainId: number; if (typeof chain?.id !== "undefined") { - chainID = chain.id; + chainId = chain.id; } const fetchData = async (selectedValue: TimeStampDate) => { try { const timeSelected = BigInt(selectedValue); - const timestamp = await getTimestamp(chainID); + const timestamp = await getTimestamp(chainId); setTimeDate(timeSelected + timestamp); } catch (error) { console.error("error", error); diff --git a/components/01-atoms/SwapModalButton.tsx b/components/01-atoms/SwapModalButton.tsx index 44f47b29..b4bcbbb1 100644 --- a/components/01-atoms/SwapModalButton.tsx +++ b/components/01-atoms/SwapModalButton.tsx @@ -73,7 +73,7 @@ export function SwapModalButton({ isLoading = false, ...props }: Props) { - const { allSelectedNftsApproved } = useContext(SwapContext); + const { approvedTokensCount } = useContext(SwapContext); const { theme } = useTheme(); if (theme === undefined) return false; @@ -86,7 +86,7 @@ export function SwapModalButton({ ButtonVariantsConfigs[variant].style, "flex items-center gap-2 disabled:pointer-events-none", aditionalStyle, - !allSelectedNftsApproved + !approvedTokensCount ? "p-medium-bold dark:p-medium-bold cursor-not-allowed" : "p-medium-bold-dark bg-[#DDF23D] ", ])} @@ -101,7 +101,7 @@ export function SwapModalButton({ @@ -110,7 +110,7 @@ export function SwapModalButton({ {label} diff --git a/components/01-atoms/SwapModalLayout.tsx b/components/01-atoms/SwapModalLayout.tsx index 9d31440c..c95787ac 100644 --- a/components/01-atoms/SwapModalLayout.tsx +++ b/components/01-atoms/SwapModalLayout.tsx @@ -60,11 +60,11 @@ export const SwapModalLayout = ({ leave="transition duration-75 ease-out" leaveFrom="transform scale-100 opacity-100" leaveTo="transform scale-95 opacity-0" - className="fixed left-1/2 top-1/2 z-50 bg-[#f8f8f8] dark:bg-[#212322] -translate-x-1/2 -translate-y-1/2 rounded-[20px] border-[#353836] " + className="w-[80%] md:w-auto fixed left-1/2 top-1/2 z-50 bg-[#f8f8f8] dark:bg-[#212322] -translate-x-1/2 -translate-y-1/2 rounded-[20px] border-[#353836] " >
@@ -78,7 +78,9 @@ export const SwapModalLayout = ({

diff --git a/components/02-molecules/ConfirmSwapModal.tsx b/components/02-molecules/ConfirmSwapModal.tsx index 25e8f62e..522c6646 100644 --- a/components/02-molecules/ConfirmSwapModal.tsx +++ b/components/02-molecules/ConfirmSwapModal.tsx @@ -15,15 +15,11 @@ import { ComposeTokenUserAssets, SwapModalSteps, packingData, -} from "@/lib/client/blockchain-data"; -import { - Asset, - makeSwap, - approveTokensBeforeSwap, -} from "@/lib/client/swap-utils"; +} from "@/lib/client/blockchain-utils"; import { SwaplaceAbi } from "@/lib/client/abi"; +import { Asset, makeSwap } from "@/lib/client/swap-utils"; +import { publicClient } from "@/lib/wallet/wallet-config"; import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants"; -import { publicClientViem } from "@/lib/wallet/wallet-config"; import { getContract } from "viem"; import { type WalletClient, useNetwork, useWalletClient } from "wagmi"; import { useContext, useEffect, useState } from "react"; @@ -44,10 +40,8 @@ export const ConfirmSwapModal = ({ timeDate, authenticatedUserTokensList, searchedUserTokensList, - allSelectedNftsApproved, + approvedTokensCount, validatedAddressToSwap, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, currentSwapModalStep, updateSwapStep, } = useContext(SwapContext); @@ -91,16 +85,7 @@ export const ConfirmSwapModal = ({ useEffect(() => { updateSwapStep(ButtonClickPossibilities.PREVIOUS_STEP); - - const fetchApprove = async () => { - await approveTokensBeforeSwap( - authenticatedUserTokensList, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, - ); - }; - fetchApprove(); - }, [authenticatedUserTokensList, allSelectedNftsApproved]); + }, [authenticatedUserTokensList]); if ( !authenticatedUserAddress?.address || @@ -124,8 +109,8 @@ export const ConfirmSwapModal = ({ const SwaplaceContract = getContract({ address: SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as `0x${string}`, + publicClient: publicClient({ chainId: chain.id }), abi: SwaplaceAbi, - publicClient: publicClientViem, }); const config = await packingData( SwaplaceContract, @@ -157,7 +142,7 @@ export const ConfirmSwapModal = ({ // }; try { - if (allSelectedNftsApproved) { + if (approvedTokensCount) { const transactionReceipt = await createSwap(swap, configurations); if (transactionReceipt != undefined) { @@ -179,7 +164,7 @@ export const ConfirmSwapModal = ({ }; const validateTokensAreApproved = () => { - if (allSelectedNftsApproved) { + if (approvedTokensCount) { if (currentSwapModalStep === SwapModalSteps.APPROVE_TOKENS) { updateSwapStep(ButtonClickPossibilities.NEXT_STEP); } @@ -246,7 +231,7 @@ export const ConfirmSwapModal = ({ { updateSwapStep(ButtonClickPossibilities.NEXT_STEP); diff --git a/components/02-molecules/ProgressStatus.tsx b/components/02-molecules/ProgressStatus.tsx index 734ee333..8199d1bc 100644 --- a/components/02-molecules/ProgressStatus.tsx +++ b/components/02-molecules/ProgressStatus.tsx @@ -1,38 +1,20 @@ import { SwapContext } from "../01-atoms"; import { ProgressBar } from "../01-atoms/ProgressBar"; -import { ADDRESS_ZERO } from "@/lib/client/constants"; -import { useContext, useEffect, useState } from "react"; +import { useContext } from "react"; export const ProgressStatus = () => { - const { authedUserSelectedNftsApprovalStatus } = useContext(SwapContext); - - const [ - authedUserSelectedApprovedItemsLenght, - setAuthedUserSelectedApprovalLenght, - ] = useState(0); - useEffect(() => { - if (authedUserSelectedNftsApprovalStatus.length) { - const approvedNftsCount = authedUserSelectedNftsApprovalStatus.filter( - (item) => item.approved !== ADDRESS_ZERO, - ).length; - - setAuthedUserSelectedApprovalLenght(approvedNftsCount); - } - }, [authedUserSelectedNftsApprovalStatus]); + const { approvedTokensCount, authenticatedUserTokensList } = + useContext(SwapContext); return (
-

- {authedUserSelectedApprovedItemsLenght + - "/" + - authedUserSelectedNftsApprovalStatus.length} -

+

{approvedTokensCount + "/" + authenticatedUserTokensList.length}

diff --git a/components/02-molecules/TokenCard.tsx b/components/02-molecules/TokenCard.tsx index 005a282c..d726357d 100644 --- a/components/02-molecules/TokenCard.tsx +++ b/components/02-molecules/TokenCard.tsx @@ -2,6 +2,7 @@ import { getTokenName } from "@/lib/client/tokens"; import { SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import { isTokenSwapApproved } from "@/lib/service/verifyTokensSwapApproval"; import { ERC20, ERC721, @@ -12,6 +13,7 @@ import { import React, { useContext, useEffect, useState } from "react"; import cc from "classcat"; import toast from "react-hot-toast"; +import { useNetwork } from "wagmi"; interface TokenCardProps { tokenData: Token; @@ -33,7 +35,6 @@ interface TokenCardProps { export enum NftCardActionType { "SELECT_NFT_FOR_SWAP", "SHOW_NFT_DETAILS", - "NFT_ONCLICK", } export enum NftCardStyleType { @@ -60,8 +61,9 @@ export const TokenCard = ({ onClickAction = NftCardActionType.SELECT_NFT_FOR_SWAP, }: TokenCardProps) => { const { authenticatedUserAddress } = useAuthenticatedUser(); + const { chain } = useNetwork(); const { - setAuthenticatedUsedTokensList, + setAuthenticatedUserTokensList, setSearchedUserTokensList, authenticatedUserTokensList, searchedUserTokensList, @@ -96,8 +98,22 @@ export const TokenCard = ({ } setDisplayableData(displayableData); + + verifyIfTokenIsApproved(); }, [tokenData]); + const verifyIfTokenIsApproved = () => { + if (!chain?.id) throw new Error("User is not connected to any network"); + + isTokenSwapApproved({ + token: tokenData, + chainId: chain?.id, + }).then(() => { + //.then((result) => { + // setIsApproved(result); + }); + }; + useEffect(() => { const currentNftIsFromAuthedUser = ownerAddress ? authenticatedUserAddress?.equals(new EthereumAddress(ownerAddress)) @@ -141,13 +157,13 @@ export const TokenCard = ({ ); if (isSelected) { - setAuthenticatedUsedTokensList((prevNftAuthUser) => + setAuthenticatedUserTokensList((prevNftAuthUser) => prevNftAuthUser.filter( (selectedNft) => selectedNft.id !== tokenData.id, ), ); } else { - setAuthenticatedUsedTokensList((prevNftAuthUser) => [ + setAuthenticatedUserTokensList((prevNftAuthUser) => [ ...prevNftAuthUser, tokenData, ]); diff --git a/components/03-organisms/SwappingShelfs.tsx b/components/03-organisms/SwappingShelfs.tsx index 715b108e..3dd96c89 100644 --- a/components/03-organisms/SwappingShelfs.tsx +++ b/components/03-organisms/SwappingShelfs.tsx @@ -21,13 +21,13 @@ export const SwappingShelfs = () => { const { validatedAddressToSwap, - setAuthenticatedUsedTokensList, + setAuthenticatedUserTokensList, setSearchedUserTokensList, setInputAddress, } = useContext(SwapContext); useEffect(() => { - setAuthenticatedUsedTokensList([]); + setAuthenticatedUserTokensList([]); setSearchedUserTokensList([]); setInputAddress(""); }, [chain]); diff --git a/components/03-organisms/TokensShelf.tsx b/components/03-organisms/TokensShelf.tsx index 0cf3bacd..5c07a6f4 100644 --- a/components/03-organisms/TokensShelf.tsx +++ b/components/03-organisms/TokensShelf.tsx @@ -3,7 +3,7 @@ import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; import { getERC721TokensFromAddress, getERC20TokensFromAddress, -} from "@/lib/client/blockchain-data"; +} from "@/lib/client/blockchain-utils"; import { EthereumAddress, Token } from "@/lib/shared/types"; import { TokensList } from "@/components/02-molecules"; import { SelectUserIcon, SwapContext } from "@/components/01-atoms"; @@ -65,7 +65,6 @@ export const TokensShelf = ({ address }: TokensShelfProps) => { if (tokensCount === 0) { setTokensQueryStatus(TokensQueryStatus.NO_RESULTS); } else { - console.log(queriedTokens); setTokensList(queriedTokens); setTokensQueryStatus(TokensQueryStatus.WITH_RESULTS); } diff --git a/lib/client/abi.ts b/lib/client/abi.ts index 1ef42e6b..246cdb36 100644 --- a/lib/client/abi.ts +++ b/lib/client/abi.ts @@ -1,4 +1,4 @@ -export const SwaplaceAbi = [ +export const SwaplaceAbi: Readonly>> = [ { inputs: [ { @@ -489,7 +489,7 @@ export const SwaplaceAbi = [ }, ] as const; -export const MockERC721Abi = [ +export const MockERC721Abi: Readonly>> = [ { inputs: [], stateMutability: "nonpayable", @@ -858,7 +858,7 @@ export const MockERC721Abi = [ }, ] as const; -export const MockERC20Abi = [ +export const MockERC20Abi: Readonly>> = [ { inputs: [], stateMutability: "nonpayable", diff --git a/lib/client/blockchain-data.ts b/lib/client/blockchain-utils.ts similarity index 73% rename from lib/client/blockchain-data.ts rename to lib/client/blockchain-utils.ts index 905911c0..ff7dc7fd 100644 --- a/lib/client/blockchain-data.ts +++ b/lib/client/blockchain-utils.ts @@ -1,6 +1,12 @@ -import { getApiKeyForNetwork, getRpcHttpUrlForNetwork } from "./constants"; +import { ADDRESS_ZERO, getApiKeyForNetwork, getNetwork } from "./constants"; import { Asset, makeAsset } from "./swap-utils"; -import { Token, ERC20, ERC721, TokenType } from "../shared/types"; +import { + Token, + ERC20, + ERC721, + TokenType, + EthereumAddress, +} from "../shared/types"; import { type GetTokensForOwnerResponse, type OwnedNftsResponse, @@ -10,18 +16,24 @@ import { } from "alchemy-sdk"; import { type WalletClient } from "wagmi"; +const INVALID_TOKEN_AMOUNT_OR_ID = BigInt(Number.MAX_SAFE_INTEGER); +const INVALID_TOKEN_SWAP_INFO = { + amountOrId: INVALID_TOKEN_AMOUNT_OR_ID, + tokenAddress: ADDRESS_ZERO as `0x${string}`, +}; + export interface ICreateSwap { walletClient: WalletClient; expireDate: bigint; - searchedUserTokensList: any[]; - authenticatedUserTokensList: any[]; + searchedUserTokensList: Token[]; + authenticatedUserTokensList: Token[]; validatedAddressToSwap: string; - authenticatedUserAddress: any; + authenticatedUserAddress: EthereumAddress; chain: number; } export interface IApproveMulticall { - abi: any; + abi: Record; functionName: string; address: `0x${string}`; args?: [any]; @@ -30,11 +42,15 @@ export interface IGetApproveSwap { tokenAddress: `0x${string}`; amountOrId: bigint; } -export interface IApproveSwap { - walletClient: any; - spender: any; + +export interface IApproveTokenSwap { + walletClient: WalletClient; + tokenContractAddress: `0x${string}`; + spender: `0x${string}`; amountOrId: bigint; - tokenContractAddress: any; + chainId: number; + token: Token; + onConfirm: (token: Token) => void; } export enum SwapModalSteps { @@ -56,7 +72,7 @@ export enum TransactionStatus { SUCCESSFUL_TRANSACTION, } -export type TokensWithSwapInfo = { +export type TokenWithSwapInfo = { tokenAddress: `0x${string}`; amountOrId: bigint; }; @@ -69,18 +85,7 @@ export async function ComposeTokenUserAssets( for (let i = 0; i < tokensList.length; i += 1) { const addr = tokensList[i]?.contract as `0x${string}`; - let amountOrId = undefined; - - switch (tokensList[i].tokenType) { - case TokenType.ERC20: - if ((tokensList[i] as ERC20).rawBalance) { - amountOrId = BigInt((tokensList[i] as ERC20).rawBalance as string); - } - case TokenType.ERC721: - if (tokensList[i]?.id as unknown as number) { - amountOrId = tokensList[i]?.id as unknown as number; - } - } + const amountOrId = getTokenAmountOrId(tokensList[i]); if (amountOrId !== undefined && addr !== undefined) { const assetPromise = makeAsset(addr, amountOrId).then((asset) => { @@ -95,10 +100,45 @@ export async function ComposeTokenUserAssets( return tokenAssetArray; } +export const getTokenAmountOrId = (token: Token): bigint => { + /* ERC20 tokens have an transaction amount while ERC721, a token ID */ + let tokenAmountOrTokenId = undefined; + + switch (token.tokenType) { + case TokenType.ERC20: + if ((token as ERC20).rawBalance) { + tokenAmountOrTokenId = (token as ERC20).rawBalance as string; + } + case TokenType.ERC721: + if (token.id) { + tokenAmountOrTokenId = token.id as string; + } + } + + if (typeof tokenAmountOrTokenId === "undefined") + return BigInt(INVALID_TOKEN_AMOUNT_OR_ID); + else return BigInt(tokenAmountOrTokenId); +}; + +export function getTokenInfoBeforeSwap(token: Token): TokenWithSwapInfo { + const amountOrId = getTokenAmountOrId(token); + + const contractAddress = token.contract; + + if (amountOrId !== undefined && contractAddress !== undefined) { + return { + tokenAddress: contractAddress as `0x${string}`, + amountOrId: amountOrId, + }; + } else { + return INVALID_TOKEN_SWAP_INFO; + } +} + export function getTokensInfoBeforeSwap( tokensList: Token[], -): TokensWithSwapInfo[] { - const tokensWithInfo: TokensWithSwapInfo[] = []; +): TokenWithSwapInfo[] { + const tokensWithInfo: TokenWithSwapInfo[] = []; for (let i = 0; i < tokensList.length; i++) { let nftAmountOrTokenId = undefined; @@ -136,19 +176,19 @@ export const getERC721TokensFromAddress = async ( chainId: number, ) => { const networkAPIKey = getApiKeyForNetwork.get(chainId); - const networkRPCHttpURL = getRpcHttpUrlForNetwork.get(chainId); + const networkName = getNetwork.get(chainId); if (!networkAPIKey) { throw new Error("No API Key for this network."); } - if (!networkRPCHttpURL) { - throw new Error("No RPC URL for this network."); + if (!networkName) { + throw new Error("No Network Name is defined for this network."); } const config = { apiKey: networkAPIKey, - network: networkRPCHttpURL, + network: networkName, }; const alchemy = new Alchemy(config); @@ -183,18 +223,18 @@ export const getERC20TokensFromAddress = async ( chainId: number, ): Promise => { const alchemyApiKey = getApiKeyForNetwork.get(chainId); - const alchemyRPCHttpURL = getRpcHttpUrlForNetwork.get(chainId); + const networkName = getNetwork.get(chainId); if (!alchemyApiKey) { throw new Error("No API Key for this network."); } - if (!alchemyRPCHttpURL) { - throw new Error("No RPC URL for this network."); + if (!networkName) { + throw new Error("No Network Name is defined for this network."); } const config = { apiKey: alchemyApiKey, - network: alchemyRPCHttpURL, + network: networkName, }; const alchemy = new Alchemy(config); @@ -285,7 +325,7 @@ const parseAlchemyERC20Tokens = (tokens: OwnedToken[]): ERC20[] => { // return swap; // } -export interface IArrayStatusTokenApproved { +export interface TokenApprovalData { approved: `0x${string}`; tokenAddress: `0x${string}`; amountOrId: bigint; diff --git a/lib/client/constants.ts b/lib/client/constants.ts index 33a7512e..caa12bde 100644 --- a/lib/client/constants.ts +++ b/lib/client/constants.ts @@ -1,6 +1,5 @@ import { Network } from "alchemy-sdk"; -/* eslint-disable prefer-const */ export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; export const WIDE_SCREEN_SIZE = 1279; @@ -65,21 +64,40 @@ export interface AlchemyERC721 { // styleType?: NftCardStyleType; // } -export let getApiKeyForNetwork: Map = new Map([ +export const getApiKeyForNetwork: Map = new Map([ [ChainInfo.SEPOLIA.id, process.env.NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY ?? ""], [ChainInfo.MUMBAI.id, process.env.NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY ?? ""], ]); -export let getRpcHttpUrlForNetwork: Map = new Map([ +export const getNetwork: Map = new Map([ [ChainInfo.SEPOLIA.id, Network.ETH_SEPOLIA], [ChainInfo.MUMBAI.id, Network.MATIC_MUMBAI], ]); +export const getRpcHttpUrlForNetwork: Map = new Map([ + [ChainInfo.SEPOLIA.id, `https://eth-sepolia.g.alchemy.com/v2/`], + [ChainInfo.MUMBAI.id, "https://polygon-mumbai.g.alchemy.com/v2/"], +]); + +export const getAPIKeyForNetwork: Map = new Map([ + [ChainInfo.SEPOLIA.id, process.env.NEXT_PUBLIC_ALCHEMY_SEPOLIA_KEY], + [ChainInfo.MUMBAI.id, process.env.NEXT_PUBLIC_ALCHEMY_MUMBAI_KEY], +]); + export const SWAPLACE_SMART_CONTRACT_ADDRESS = { [ChainInfo.SEPOLIA.id]: "0x24809b2b374c5d70c2BdA6d65290e3fa3a2b378d", [ChainInfo.MUMBAI.id]: "0x420696541dc0ec9643409C64d0Ba39dD429Eb34b", }; +export const getCurrentNetworkHttpUrl = (chainId: number) => { + const httpUrl = getRpcHttpUrlForNetwork.get(chainId); + const key = getAPIKeyForNetwork.get(chainId); + + if (!key) throw new Error(`No API key is defined for chain ID: ${chainId}`); + + return httpUrl + key; +}; + //SEPOLIA MOCKS export const MOCKERC721 = "0x83dB434Db5014e24AdF5962457334122F1d4ab13"; export const MOCKERC20 = "0x31a59e0f7fD0724545fCD912bcC2c5A1debddd0C"; diff --git a/lib/client/hooks/subgraphQueries.ts b/lib/client/hooks/subgraphQueries.ts index e1603657..516a31d4 100644 --- a/lib/client/hooks/subgraphQueries.ts +++ b/lib/client/hooks/subgraphQueries.ts @@ -31,16 +31,14 @@ export const getGraphQuery = async () => { }; try { - const response = await axios(config); - console.log(JSON.stringify(response.data, null, 2)); - console.log(response.data.errors); + await axios(config); } catch (error) { console.error(error); } }; getGraphQuery() - .then((result) => console.log(result)) + .then((result) => result) .catch((error) => { console.error(error); }); diff --git a/lib/client/hooks/useAuthenticatedUser.tsx b/lib/client/hooks/useAuthenticatedUser.tsx index 7f50b286..75013a5a 100644 --- a/lib/client/hooks/useAuthenticatedUser.tsx +++ b/lib/client/hooks/useAuthenticatedUser.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { ADDRESS_ZERO, getRpcHttpUrlForNetwork } from "../constants"; +import { ADDRESS_ZERO, getNetwork } from "../constants"; import { EthereumAddress } from "../../shared/types"; import { signOut, useSession } from "next-auth/react"; import { useEffect, useState } from "react"; @@ -24,10 +24,7 @@ export const useAuthenticatedUser = (): AuthenticatedUserHook => { useState(true); useEffect(() => { - if ( - typeof chain?.id === "number" && - !getRpcHttpUrlForNetwork.get(chain?.id) - ) { + if (typeof chain?.id === "number" && !getNetwork.get(chain?.id)) { disconnect(); return; } diff --git a/lib/client/swap-utils.ts b/lib/client/swap-utils.ts index 97d7358b..de01aaa6 100644 --- a/lib/client/swap-utils.ts +++ b/lib/client/swap-utils.ts @@ -1,22 +1,22 @@ -import { - IArrayStatusTokenApproved, - getTokensInfoBeforeSwap, -} from "./blockchain-data"; +import { TokenApprovalData, getTokensInfoBeforeSwap } from "./blockchain-utils"; import { ADDRESS_ZERO } from "./constants"; import { getTimestamp } from "./utils"; import { EthereumAddress, Token } from "../shared/types"; import { getMultipleNftsApprovalStatus } from "../service/verifyTokensSwapApproval"; import { Dispatch, SetStateAction } from "react"; -export const approveTokensBeforeSwap = async ( +export const batchApproveTokenSwap = async ( + chainId: number, tokensList: Token[], - setNftsApprovalStatus: Dispatch>, + setNftsApprovalStatus: Dispatch>, setNftsAreAllApproved: (areApproved: boolean) => void, ) => { const nftsToSwapFromAuthedUser = getTokensInfoBeforeSwap(tokensList); + try { const result = await getMultipleNftsApprovalStatus( nftsToSwapFromAuthedUser, + chainId, ); const nftsApprovalStatus = result.map((approved, index) => ({ diff --git a/lib/service/approveSwap.ts b/lib/service/approveSwap.ts index d5c1d052..0f544c85 100644 --- a/lib/service/approveSwap.ts +++ b/lib/service/approveSwap.ts @@ -1,34 +1,58 @@ -import { MockERC721Abi } from "../client/abi"; -import { IApproveSwap } from "../client/blockchain-data"; -import { publicClientViem } from "../wallet/wallet-config"; -import { type Hash, type TransactionReceipt, encodeFunctionData } from "viem"; +import { MockERC20Abi, MockERC721Abi } from "../client/abi"; +import { IApproveTokenSwap } from "../client/blockchain-utils"; +import { TokenType } from "../shared/types"; +import { publicClient } from "../wallet/wallet-config"; +import { type Hash, type TransactionReceipt } from "viem"; export async function approveSwap({ walletClient, spender, tokenContractAddress, amountOrId, -}: IApproveSwap): Promise { - const data = encodeFunctionData({ - abi: MockERC721Abi, - functionName: "approve", - args: [spender, amountOrId], - }); + chainId, + token, + onConfirm, +}: IApproveTokenSwap): Promise { + const abi = + token.tokenType === TokenType.ERC20 ? MockERC20Abi : MockERC721Abi; + const functionName = "approve"; try { - const transactionHash: Hash = await walletClient.sendTransaction({ - data: data, - to: tokenContractAddress, + const transactionHash: Hash = await walletClient.writeContract({ + account: walletClient.account.address as `0x${string}`, + address: tokenContractAddress, + args: [spender, amountOrId], + functionName, + abi, }); + onConfirm(token); - const transactionReceipt = await publicClientViem.waitForTransactionReceipt( - { + let txReceipt = {} as TransactionReceipt; + + while (txReceipt.blockHash === undefined) { + /* + It is guaranteed that at some point we'll have a valid TransactionReceipt in here. + If we had a valid transaction sent (which is confirmed at this point by the try/catch block), + it is a matter of waiting the transaction to be mined in order to know whether it was successful or not. + + So why are we using a while loop here? + - Because it is possible that the transaction was not yet mined by the time + we reach this point. So we keep waiting until we have a valid TransactionReceipt. + */ + const transactionReceipt = await publicClient({ + chainId, + }).waitForTransactionReceipt({ hash: transactionHash, - }, - ); + }); + + if (transactionReceipt.blockHash) { + txReceipt = transactionReceipt; + } + } - return transactionReceipt; + return txReceipt; } catch (error) { + console.log(error); console.error(error); } } diff --git a/lib/service/createSwap.ts b/lib/service/createSwap.ts index 118283d1..95ed5c3f 100644 --- a/lib/service/createSwap.ts +++ b/lib/service/createSwap.ts @@ -1,6 +1,6 @@ import { Swap } from "../client/swap-utils"; import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "../client/constants"; -import { publicClientViem } from "../wallet/wallet-config"; +import { publicClient } from "../wallet/wallet-config"; import { encodeFunctionData } from "viem"; export interface SwapUserConfiguration { @@ -100,7 +100,6 @@ export async function createSwap( }, ], }); - try { const transactionHash = await configurations.walletClient.sendTransaction({ data: data, @@ -109,11 +108,11 @@ export async function createSwap( ] as `0x${string}`, }); - const transactionReceipt = await publicClientViem.waitForTransactionReceipt( - { - hash: transactionHash, - }, - ); + const transactionReceipt = await publicClient({ + chainId: configurations.chain, + }).waitForTransactionReceipt({ + hash: transactionHash, + }); return transactionReceipt; } catch (error) { diff --git a/lib/service/verifyTokensSwapApproval.ts b/lib/service/verifyTokensSwapApproval.ts index de4efabc..6e45cddd 100644 --- a/lib/service/verifyTokensSwapApproval.ts +++ b/lib/service/verifyTokensSwapApproval.ts @@ -1,27 +1,49 @@ import { IApproveMulticall, - IApproveSwap, IGetApproveSwap, -} from "../client/blockchain-data"; -import { publicClientViem } from "../wallet/wallet-config"; + getTokenInfoBeforeSwap, +} from "../client/blockchain-utils"; +import { publicClient } from "../wallet/wallet-config"; import { MockERC721Abi } from "../client/abi"; +import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "../client/constants"; +import { Token, TokenType } from "../shared/types"; -export async function getApprovedSwap({ - tokenContractAddress, - amountOrId, -}: IApproveSwap) { - const data = await publicClientViem.readContract({ - abi: MockERC721Abi, - functionName: "getApproved", - address: tokenContractAddress, - args: [amountOrId], - }); +export async function isTokenSwapApproved({ + token, + chainId, +}: { + token: Token; + chainId: number; +}): Promise { + const tokenSwapInfo = getTokenInfoBeforeSwap(token); + + let data; + if (token.tokenType === TokenType.ERC20) { + // Todo: implement ERC20 approval amount checker + return false; + } else if (token.tokenType === TokenType.ERC721) { + const tokenTypeAbi = MockERC721Abi; + const getApprovedStatusMethod = "getApproved"; + data = await publicClient({ chainId }).readContract({ + abi: tokenTypeAbi, + functionName: getApprovedStatusMethod, + address: tokenSwapInfo.tokenAddress, + args: [tokenSwapInfo.amountOrId], + }); + } - return data; + /* + Whenever a token is approved to be exchanged by a given Smart-Contract, + the returned string of 'getApproved()' informs the given Smart-Contract + address. If the token is not approved to be swap by this given + Smart-Contract, 'getApproved()' returns 'ADDRESS_ZERO' + */ + return data === SWAPLACE_SMART_CONTRACT_ADDRESS[chainId]; } export async function getMultipleNftsApprovalStatus( nftsApprove: IGetApproveSwap[], + chainId: number, ) { const approvedCall: IApproveMulticall[] = nftsApprove.map((data) => ({ abi: MockERC721Abi, @@ -30,7 +52,7 @@ export async function getMultipleNftsApprovalStatus( args: [data.amountOrId], })); - const approvedTokens = await publicClientViem.multicall({ + const approvedTokens = await publicClient({ chainId }).multicall({ contracts: approvedCall, allowFailure: false, }); diff --git a/lib/wallet/wallet-config.ts b/lib/wallet/wallet-config.ts index b3d3de78..38805cef 100644 --- a/lib/wallet/wallet-config.ts +++ b/lib/wallet/wallet-config.ts @@ -1,4 +1,4 @@ -import { getRpcHttpUrlForNetwork } from "../client/constants"; +import { getCurrentNetworkHttpUrl } from "../client/constants"; import { polygonMumbai, sepolia } from "@wagmi/core/chains"; import { configureChains, createConfig } from "wagmi"; import { @@ -11,24 +11,18 @@ import { } from "@rainbow-me/rainbowkit/wallets"; import { connectorsForWallets } from "@rainbow-me/rainbowkit"; import { jsonRpcProvider } from "wagmi/providers/jsonRpc"; -import { createPublicClient, http } from "viem"; export const { chains, webSocketPublicClient, publicClient } = configureChains( [sepolia, polygonMumbai], [ jsonRpcProvider({ rpc: (chain) => ({ - http: getRpcHttpUrlForNetwork.get(chain.id) ?? "", + http: getCurrentNetworkHttpUrl(chain.id), }), }), ], ); -export const publicClientViem = createPublicClient({ - chain: sepolia, - transport: http(), -}); - const connectorArgs = { appName: "Swaplace dApp", chains: [sepolia, polygonMumbai], From f93d445c036382dbb305fdc37bee4d2607f610f8 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Wed, 28 Feb 2024 20:49:33 -0300 Subject: [PATCH 188/305] feat: Merged develop updates --- components/01-atoms/NftsCardApprovedList.tsx | 164 ------------------- components/02-molecules/NftsList.tsx | 46 ------ components/02-molecules/TokensList.tsx | 33 +++- 3 files changed, 25 insertions(+), 218 deletions(-) delete mode 100644 components/01-atoms/NftsCardApprovedList.tsx delete mode 100644 components/02-molecules/NftsList.tsx diff --git a/components/01-atoms/NftsCardApprovedList.tsx b/components/01-atoms/NftsCardApprovedList.tsx deleted file mode 100644 index 52f3409a..00000000 --- a/components/01-atoms/NftsCardApprovedList.tsx +++ /dev/null @@ -1,164 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { - ADDRESS_ZERO, - NFT, - SWAPLACE_SMART_CONTRACT_ADDRESS, -} from "@/lib/client/constants"; -import { SwapContext } from "@/components/01-atoms"; -import { - NftCard, - NftCardActionType, - NftCardStyleType, -} from "@/components/02-molecules"; -import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { updateNftsToSwapApprovalStatus } from "@/lib/client/swap-utils"; -import { IApproveSwap } from "@/lib/client/blockchain-data"; -import { approveSwap } from "@/lib/service/approveSwap"; -import cc from "classcat"; -import { useContext, useEffect } from "react"; -import toast from "react-hot-toast"; -import { useNetwork, useWalletClient } from "wagmi"; -import { hexToNumber } from "viem"; - -export const NftsCardApprovedList = () => { - const { authenticatedUserAddress } = useAuthenticatedUser(); - const { chain } = useNetwork(); - const { data: walletClient } = useWalletClient(); - - const { - nftAuthUser, - authedUserSelectedNftsApprovalStatus, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, - allSelectedNftsApproved, - } = useContext(SwapContext); - - useEffect(() => { - const fetchApprove = async () => { - await updateNftsToSwapApprovalStatus( - nftAuthUser, - setAuthedUserNftsApprovalStatus, - setAllSelectedNftsAreApproved, - ); - }; - fetchApprove(); - }, [nftAuthUser, allSelectedNftsApproved]); - - if (!authenticatedUserAddress?.address) { - return null; - } - let chainId: number; - const handleApprove = async (nft: NFT) => { - if (typeof chain?.id != "undefined") { - chainId = chain?.id; - } - - const swapData: IApproveSwap = { - walletClient: walletClient, - spender: SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as `0x${string}`, - tokenContractAddress: nft.contract?.address, - amountOrId: BigInt(hexToNumber(nft.id?.tokenId)), - }; - - try { - const transactionReceipt = await approveSwap(swapData); - if (transactionReceipt != undefined) { - toast.success("Approval successfully"); - return transactionReceipt; - } else { - toast.error("Approval Failed"); - } - } catch (error) { - toast.error("Approval Rejected"); - console.error(error); - } - }; - - const validateApprovalTokens = (arraynftApproval: any[]) => { - const isValidApproved = !arraynftApproval.some((token) => { - return token.approved != SWAPLACE_SMART_CONTRACT_ADDRESS[chainId]; - }); - - setAllSelectedNftsAreApproved(isValidApproved); - }; - - const approveNftForSwapping = async (nft: NFT, index: number) => { - if (typeof chain?.id != "undefined") { - chainId = chain?.id; - } - if ( - authedUserSelectedNftsApprovalStatus[index]?.approved === - SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] - ) { - toast.error("Token already approved."); - } else { - await handleApprove(nft).then((result) => { - if (result != undefined) { - const nftWasApproved = (authedUserSelectedNftsApprovalStatus[ - index - ].approved = SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as any); - - setAuthedUserNftsApprovalStatus([nftWasApproved]); - } - validateApprovalTokens(authedUserSelectedNftsApprovalStatus); - }); - } - }; - - return ( -
-
- {nftAuthUser.map((nft, index) => ( -
approveNftForSwapping(nft, index)} - > -
- -
-
-
- {authedUserSelectedNftsApprovalStatus[index]?.approved === - ADDRESS_ZERO ? ( -

- {nftAuthUser[index].contractMetadata?.name} -

- ) : ( -

- {nftAuthUser[index].contractMetadata?.name} -

- )} -
-
- {authedUserSelectedNftsApprovalStatus[index]?.approved === - ADDRESS_ZERO ? ( -

- PENDING APPROVAL -

- ) : ( -
-

APPROVED

-
- )} -
-
-
- ))} -
-
- ); -}; diff --git a/components/02-molecules/NftsList.tsx b/components/02-molecules/NftsList.tsx deleted file mode 100644 index 4c0184c6..00000000 --- a/components/02-molecules/NftsList.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { NFT } from "@/lib/client/constants"; -import { NftCard } from "@/components/02-molecules"; -import { EmptyNftsCards, SwapAddTokenCard } from "@/components/01-atoms"; - -/* eslint-disable react/jsx-key */ -interface INftsList { - nftsList: NFT[]; - ownerAddress: string | null; - variant: "your" | "their"; -} - -/** - * - * This component receives the data of multiple nfts and create its cards - * @param nftsList - * @param ownerAddress - * - * @returns NftsList - */ - -export const NftsList = ({ nftsList, ownerAddress, variant }: INftsList) => { - const emptySquares = EmptyNftsCards(nftsList.length, 15, 30, 30, 30); - const addTokenSquare = SwapAddTokenCard(); - const nftSquares = nftsList.map((nft: NFT, index) => ( -
- -
- )); - - if (variant === "your") { - emptySquares.pop(); // Removes the last element to fill with addToken - const allSquares = [...nftSquares, ...emptySquares, addTokenSquare]; - return ( -
- {allSquares} -
- ); - } else { - const allSquares = [...nftSquares, ...emptySquares]; - return ( -
- {allSquares} -
- ); - } -}; diff --git a/components/02-molecules/TokensList.tsx b/components/02-molecules/TokensList.tsx index 26b5dca8..912bd70b 100644 --- a/components/02-molecules/TokensList.tsx +++ b/components/02-molecules/TokensList.tsx @@ -1,10 +1,11 @@ import { TokenCard } from "@/components/02-molecules"; -import { TokenCardsPlaceholder } from "@/components/01-atoms"; +import { SwapAddTokenCard, TokenCardsPlaceholder } from "@/components/01-atoms"; import { Token } from "@/lib/shared/types"; export interface TokensListProps { tokensList: Token[]; ownerAddress: string | null; + variant: "your" | "their"; } /** @@ -16,7 +17,11 @@ export interface TokensListProps { * @returns TokensList */ -export const TokensList = ({ tokensList, ownerAddress }: TokensListProps) => { +export const TokensList = ({ + tokensList, + ownerAddress, + variant, +}: TokensListProps) => { const placeholders = TokenCardsPlaceholder(tokensList.length, 15, 30, 30, 30); const tokenCards = tokensList.map((token: Token, index) => (
@@ -24,11 +29,23 @@ export const TokensList = ({ tokensList, ownerAddress }: TokensListProps) => {
)); - const allSquares = [...tokenCards, ...placeholders]; + let allSquares = [...tokenCards, ...placeholders]; - return ( -
- {allSquares} -
- ); + const addTokenSquare = SwapAddTokenCard(); + + if (variant === "your") { + placeholders.pop(); // Removes the last element to fill with addToken + allSquares = [...allSquares, addTokenSquare]; + return ( +
+ {allSquares} +
+ ); + } else { + return ( +
+ {allSquares} +
+ ); + } }; From 67dfd214df4ff5205b2a8d3b26b18b17e4992e90 Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Thu, 29 Feb 2024 01:02:45 -0300 Subject: [PATCH 189/305] feat: Created ApproveTokenCard component --- components/01-atoms/ApprovedTokenCards.tsx | 150 +-------------- components/01-atoms/SearchBar.tsx | 11 +- components/01-atoms/SwapContext.tsx | 1 + components/01-atoms/SwapExpireTime.tsx | 6 +- components/01-atoms/Tooltip.tsx | 2 +- components/01-atoms/WalletSidebarTemplate.tsx | 4 +- components/01-atoms/icons/PowerIcon.tsx | 2 +- components/02-molecules/ConfirmSwapModal.tsx | 7 +- components/02-molecules/OfferSummary.tsx | 2 +- components/02-molecules/TheHeader.tsx | 4 +- components/02-molecules/TheSidebarHeader.tsx | 3 +- components/02-molecules/TokenCard.tsx | 55 ++---- components/03-organisms/ApproveTokenCard.tsx | 173 ++++++++++++++++++ .../03-organisms/{index.tsx => index.ts} | 1 + lib/client/blockchain-utils.ts | 26 +-- lib/client/constants.ts | 15 +- lib/client/contexts/SidebarContext.tsx.tsx | 25 ++- lib/client/hooks/useENSData.tsx | 7 + lib/client/swap-utils.ts | 8 +- lib/service/approveSwap.ts | 17 +- lib/service/verifyTokensSwapApproval.ts | 47 ++--- 21 files changed, 312 insertions(+), 254 deletions(-) create mode 100644 components/03-organisms/ApproveTokenCard.tsx rename components/03-organisms/{index.tsx => index.ts} (77%) diff --git a/components/01-atoms/ApprovedTokenCards.tsx b/components/01-atoms/ApprovedTokenCards.tsx index 98328981..460e0250 100644 --- a/components/01-atoms/ApprovedTokenCards.tsx +++ b/components/01-atoms/ApprovedTokenCards.tsx @@ -1,36 +1,18 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { SWAPLACE_SMART_CONTRACT_ADDRESS } from "@/lib/client/constants"; +import { ApproveTokenCard } from "../03-organisms"; import { SwapContext } from "@/components/01-atoms"; -import { TokenCard, NftCardStyleType } from "@/components/02-molecules"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; -import { - IApproveTokenSwap, - getTokenAmountOrId, -} from "@/lib/client/blockchain-utils"; -import { approveSwap } from "@/lib/service/approveSwap"; -import { isTokenSwapApproved } from "@/lib/service/verifyTokensSwapApproval"; -import { getTokenName } from "@/lib/client/tokens"; import { Token } from "@/lib/shared/types"; -import cc from "classcat"; import { useContext, useEffect, useState } from "react"; -import toast from "react-hot-toast"; -import { type WalletClient, useNetwork, useWalletClient } from "wagmi"; -import { type TransactionReceipt } from "viem"; export const ApprovedTokenCards = () => { const { authenticatedUserAddress } = useAuthenticatedUser(); - const { chain } = useNetwork(); - const { data: walletClient } = useWalletClient(); - const [tokensBeingApproved, setTokensBeingApproved] = useState([]); const [tokensApprovedForSwap, setTokensApprovedForSwap] = useState( [], ); - const { - authenticatedUserTokensList, - setApprovedTokensCount, - approvedTokensCount, - } = useContext(SwapContext); + const { authenticatedUserTokensList, setApprovedTokensCount } = + useContext(SwapContext); useEffect(() => { setApprovedTokensCount(0); @@ -40,133 +22,21 @@ export const ApprovedTokenCards = () => { return null; } - let chainId: number; + const addNewTokenToApprovedList = (token: Token) => { + setTokensApprovedForSwap([...tokensApprovedForSwap, token]); - const handleApprove = async ( - token: Token, - loadingCallback: (token: Token) => void, - ): Promise => { - if (!chain?.id || !walletClient) { - throw new Error("User's wallet is not connected"); - } - - if (!token.contract) - throw new Error(`Token contract is not defined for: ${token}`); - - const swapData: IApproveTokenSwap = { - walletClient: walletClient as WalletClient, - spender: SWAPLACE_SMART_CONTRACT_ADDRESS[chainId] as `0x${string}`, - tokenContractAddress: token.contract as `0x${string}`, - amountOrId: getTokenAmountOrId(token), - chainId: chain.id, - token, - onConfirm: loadingCallback, - }; - - try { - const transactionReceipt = await approveSwap(swapData); - - if (transactionReceipt != undefined) { - toast.success("Approved successfully"); - setTokensApprovedForSwap([...tokensApprovedForSwap, token]); - return transactionReceipt; - } else { - toast.error("Approval failed"); - } - } catch (error) { - // TODO: map error scenarios and create corresponding error triggers - toast.error("Approval rejected"); - console.error(error); - } - }; - - const addTokenToLoadingState = (token: Token) => { - setTokensBeingApproved([...tokensBeingApproved, token]); - }; - - const handleTokenApproval = async (token: Token) => { - if (typeof chain?.id != "undefined") { - chainId = chain?.id; - } else { - throw new Error("User is not connected to any network"); - } - - const isApproved = await isTokenSwapApproved({ - token, - chainId, - }); - - if (isApproved) { - setTokensApprovedForSwap([...tokensApprovedForSwap, token]); - toast.success("Token approved."); - } else { - await handleApprove(token, addTokenToLoadingState).then((isApproved) => { - if (typeof isApproved !== "undefined") { - setApprovedTokensCount(approvedTokensCount + 1); - } - - setTokensBeingApproved( - tokensBeingApproved.filter((tk) => tk === token), - ); - }); - } + setApprovedTokensCount([...tokensApprovedForSwap, token].length); }; return (
{authenticatedUserTokensList.map((token, index) => ( -
handleTokenApproval(token)} - > -
- -
-
-
- {!tokensApprovedForSwap.includes(token) ? ( -

- {getTokenName(authenticatedUserTokensList[index])} -

- ) : ( -

- {getTokenName(authenticatedUserTokensList[index])} -

- )} -
-
- {tokensBeingApproved.includes(token) ? ( -

- WAITING BLOCKCHAIN CONFIRMATION -

- ) : !tokensApprovedForSwap.includes(token) ? ( -

- CLICK TO APPROVE -

- ) : ( -
-

APPROVED

-
- )} -
-
-
+ token={token} + /> ))}
diff --git a/components/01-atoms/SearchBar.tsx b/components/01-atoms/SearchBar.tsx index e2d1cd8b..bdadc193 100644 --- a/components/01-atoms/SearchBar.tsx +++ b/components/01-atoms/SearchBar.tsx @@ -3,6 +3,8 @@ /* eslint-disable import/no-named-as-default-member */ import { MagnifyingGlassIcon, SwapContext } from "@/components/01-atoms"; import { useAuthenticatedUser } from "@/lib/client/hooks/useAuthenticatedUser"; +import { ADDRESS_ZERO } from "@/lib/client/constants"; +import { EthereumAddress } from "@/lib/shared/types"; import { useContext, useEffect } from "react"; import { useTheme } from "next-themes"; import { ENS } from "web3-eth-ens"; @@ -15,7 +17,6 @@ export const SearchBar = () => { inputAddress, validateAddressToSwap, setUserJustValidatedInput, - setValidatedAddressToSwap, } = useContext(SwapContext); const { authenticatedUserAddress } = useAuthenticatedUser(); @@ -67,11 +68,10 @@ export const SearchBar = () => { }; useEffect(() => { - setValidatedAddressToSwap(""); const requestDelay = setTimeout(() => { setUserJustValidatedInput(false); getUserAddress(); - }, 750); + }, 1500); return () => clearTimeout(requestDelay); }, [inputAddress]); @@ -101,6 +101,11 @@ export const SearchBar = () => { `h-11 w-full border-gray-100 focus:ring-0 focus:ring-transparent focus:outline-none focus-visible:border-gray-300 placeholder:p-small dark:border-none dark:bg-transparent`, ])} + onKeyDown={(e) => { + if (authenticatedUserAddress && e.key === "Enter") { + validateAddressToSwap(authenticatedUserAddress, inputAddress); + } + }} placeholder="Search username, address or ENS" onChange={({ target }) => setInputAddress(target.value)} /> diff --git a/components/01-atoms/SwapContext.tsx b/components/01-atoms/SwapContext.tsx index 4dbc08d9..8e4bd93e 100644 --- a/components/01-atoms/SwapContext.tsx +++ b/components/01-atoms/SwapContext.tsx @@ -119,6 +119,7 @@ export const SwapContextProvider = ({ children }: any) => { setValidatedAddressToSwap(searchedAddress); toast.success("Searching Address"); } else { + setValidatedAddressToSwap(""); toast.error( "Your input is not a valid address and neither some registered ENS domain", ); diff --git a/components/01-atoms/SwapExpireTime.tsx b/components/01-atoms/SwapExpireTime.tsx index 10b794f0..c569f56d 100644 --- a/components/01-atoms/SwapExpireTime.tsx +++ b/components/01-atoms/SwapExpireTime.tsx @@ -41,7 +41,7 @@ export const SwapExpireTime = () => { return (
-
+
Expires in
@@ -49,13 +49,13 @@ export const SwapExpireTime = () => { + +
+ +
+ +
+
+ + ); +}; diff --git a/components/01-atoms/Tooltip.tsx b/components/01-atoms/Tooltip.tsx index becaea78..9f60cd2d 100644 --- a/components/01-atoms/Tooltip.tsx +++ b/components/01-atoms/Tooltip.tsx @@ -22,7 +22,7 @@ export const Tooltip = ({ position, content, children }: TooltipProps) => (