From 160ce1cf21915cbce49cbd41fdfe54743f122f34 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Mon, 23 Dec 2024 08:44:07 +0200 Subject: [PATCH] added other coins --- src/App.tsx | 64 +++++++-- src/assets/img/arrr.png | Bin 0 -> 1429 bytes src/assets/img/btc.png | Bin 0 -> 1982 bytes src/assets/img/dgb.png | Bin 0 -> 4917 bytes src/assets/img/doge.png | Bin 0 -> 1798 bytes src/assets/img/ltc.png | Bin 0 -> 1480 bytes src/assets/img/qort.png | Bin 0 -> 1907 bytes src/assets/img/rvn.png | Bin 0 -> 2405 bytes src/components/Grids/OngoingTrades.tsx | 34 +++-- src/components/Grids/TradeOffers.tsx | 142 ++++++++++++++----- src/components/Terms.tsx | 6 +- src/components/header/Header.tsx | 76 ++++++++++- src/components/sell/CreateSell.tsx | 40 ++++-- src/components/sell/TradeBotList.tsx | 181 +++++++++++++++++-------- src/contexts/gameContext.ts | 12 +- src/pages/Home/Home.tsx | 6 +- 16 files changed, 425 insertions(+), 136 deletions(-) create mode 100644 src/assets/img/arrr.png create mode 100644 src/assets/img/btc.png create mode 100644 src/assets/img/dgb.png create mode 100644 src/assets/img/doge.png create mode 100644 src/assets/img/ltc.png create mode 100644 src/assets/img/qort.png create mode 100644 src/assets/img/rvn.png diff --git a/src/App.tsx b/src/App.tsx index 46c2081..2fb3bd8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import ReactGA from "react-ga4"; import "./App.css"; import socketService from "./services/socketService"; @@ -71,7 +71,12 @@ export async function sendRequestToExtension( function App() { const [userInfo, setUserInfo] = useState(null); const [qortBalance, setQortBalance] = useState(null); - const [ltcBalance, setLtcBalance] = useState(null); + const [balances, setBalances] = useState({}); + const [selectedCoin, setSelectedCoin] = useState("LITECOIN"); + + const foreignCoinBalance = useMemo(()=> { + return balances[selectedCoin] || null + }, [balances, selectedCoin]) const [isAuthenticated, setIsAuthenticated] = useState(false); const [OAuthLoading, setOAuthLoading] = useState(false); const db = useIndexedDBContext(); @@ -172,14 +177,19 @@ function App() { setQortBalance(balanceResponse.data?.value) } - const getLTCBalance = async () => { + const getLTCBalance = async (coin) => { try { const response = await qortalRequest({ action: "GET_WALLET_BALANCE", - coin: "LTC" + coin: getCoinLabel(coin) }); if(!response?.error){ - setLtcBalance(+response) + setBalances((prev)=> { + return { + ...prev, + [coin]: +response + } + }) } } catch (error) { // @@ -187,18 +197,18 @@ function App() { } useEffect(() => { - if(!userInfo?.address) return + if(!userInfo?.address || !selectedCoin) return const intervalGetTradeInfo = setInterval(() => { fetchOngoingTransactions() - getLTCBalance() + getLTCBalance(selectedCoin) getQortBalance() }, 150000) - getLTCBalance() + getLTCBalance(selectedCoin) getQortBalance() return () => { clearInterval(intervalGetTradeInfo) } - }, [userInfo?.address, isAuthenticated]) + }, [userInfo?.address, isAuthenticated, selectedCoin]) const handleMessage = async (event: any) => { @@ -208,7 +218,6 @@ function App() { setAvatar(""); setIsAuthenticated(false); setQortBalance(null) - setLtcBalance(null) localStorage.setItem("token", ""); } else if(event.data.type === "RESPONSE_FOR_TRADES"){ @@ -246,6 +255,37 @@ function App() { }; }, [userInfo?.address]); + const getCoinLabel = (coin?: string)=> { + switch(coin || selectedCoin){ + case "LITECOIN":{ + + return 'LTC' + } + case "DOGECOIN":{ + + return 'DOGE' + } + case "BITCOIN":{ + + return 'BTC' + } + case "DIGIBYTE":{ + + return 'DGB' + } + case "RAVENCOIN":{ + + return 'RVN' + } + case "PIRATECHAIN":{ + + return 'ARRR' + } + default: + return null + } + } + const gameContextValue: IContextProps = { userInfo, setUserInfo, @@ -253,7 +293,7 @@ function App() { setUserNameAvatar, onGoingTrades, fetchOngoingTransactions, - ltcBalance, + foreignCoinBalance, qortBalance, isAuthenticated, setIsAuthenticated, @@ -261,7 +301,7 @@ function App() { setOAuthLoading, updateTransactionInDB, sellOrders, - deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, isUsingGateway + deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, isUsingGateway, selectedCoin, setSelectedCoin, getCoinLabel }; diff --git a/src/assets/img/arrr.png b/src/assets/img/arrr.png new file mode 100644 index 0000000000000000000000000000000000000000..d27456576e737c1353e256810d9b84dce7b42784 GIT binary patch literal 1429 zcmV;G1#0?k}ogVt_iv;g(_nl!MG8$U!DoWdu9kkw6h-ftOt@TB<<3sK5#b z%0a@oI37WePGIvKtR6|AI9mhAv#hf;g!DQH`61I`vLh+0A4)5ZAgMw_(fIw3) zJ;zl&sHJKOrdX)Hx;#!mMwh{?4+1iNCMv%cs&_F=hEbm`q|2jkHpr9){rIV#T^^%{ zqGI`FG|T-NsX|E0@RAuy6F+A}zL1-lD6p(ZBB$8#sMK3e0-2 zyN`|tb@-8)tA&n=Zp7vthfK?qt?H*&?8Ec>6y1K*Zl$YZC?)`2i2k;rbN5(Ja(f&> z+I84U^Cc*)6S}%Am?43*v&+{5%?Ss(|8(3zHn20hJXOrjyFuJRHpKXrg=S^dV)^SF z2l1dSSLXN6@BBXR1AV4vV;|eVi@+ZM7|I3uWBCi4oxV;L$+&{tePqNO-{FT843s4> zt0X1g`RVPW&|um@5()C9DX`ECi?KogX;&s8bNr+h1Qa2GTYhodULx1%dy;)-VmsA8APs0umM;p4i-Xy#(i%@Nrq=){EG``n z8)S$XAXhDYofCb_5&*4s8%WbSm%jwg^81isSt#ifaMl(afEg7*a+^RVP@R{Xlpw?2 z%hXKPIu?O+%R)&sbZ#P2AVGhAeK+?v5vio%PTVq$g+>dewJ1n1c7n>l((*&0+sF37 z1hC4FuZp}(QZ5SWcE=w6xh%tCDC7HY^JVk?3&ug07?jk#AM% zp8|1O^(-h(zSY1=b8vN(m9}V|ZWap4hn1x0U^z0D!f$4jecbWOsfvh5d+Q34B;Czhy%(n6vZ9lYt6&UXDakYjKP`=$833&u30U=V6#}s8^*@Ag)eEW!;kNq< jH3JJkl>Q2}zXA*Z%L07o@pf>Q00000NkvXXu0mjfhXs}` literal 0 HcmV?d00001 diff --git a/src/assets/img/btc.png b/src/assets/img/btc.png new file mode 100644 index 0000000000000000000000000000000000000000..fe3fd1a030bd2736ed76748d27e6584b3fa05c3a GIT binary patch literal 1982 zcmV;v2SNCWP)htPv-zHc{0_qe;RVIF+Z!7aDH+~!cJ9zWE z0z3R;&-88FK?e2QLmp!@E8cvh&hc=%{kbT8{6vWNHYd)RK99@$W6Yf$C}t1aw#Jzg z0V;Sa!^E?jk>}QSm5SwX6l)KBQTk+0IO|oeTiQv=s9ZvBZmmTrZ`ziI&lxG$;Z&v6ZUQj_sWG~M))W^e7D$CuHznMHr>Q@{nSfDQWq}b2MbIgTT zz^IxC6f5m)AyTYIo(7ztPO6RN45fh8bmc!vp{zk(9*5z6*bt5knS!?+5r9(7+s`Og z?bu8S)%ld|@)Abn>wnn39_;7E^Qti19)(pp?UZ&|FD+GddH97GzI-gMPL6m?%H8Hf z;BTPqMk*8w0Dl_&ZDq&7%d6~1XOj+Y*lnpJ?8F$`y-}IZHKxuO#X?@LytmFKZ7cjp zm4`i*Ihj;x7-&P-YUihk;4^t|1PduCvl(bi0LA>&TAed0Bbo?>P7amrmG>zweyU3w zysJEYn(tq0utMD!<@h6odbVIvDn(&+f_WHr_a)eS%A;Q$({d2!R!ywkXPrCd6#^(F zE{%&VAxye_@kptbl5T=h8B2ZFK(TUCE2=^P6o8w1j#TaCuT9$ZYHYq2>ZO~Y(7LeL zlI$ln^MPu<3X>9tK5KXD?jqUG#B*OK+el}f^+}HBMpaA}!G0FB)vW^6VL#I<9!vvc zvui_j+0SthPjEQFzdcrkmTd*}6g5Giqr6@n7oAlwe?FK!4{E5NwMc{tc%(KO0l2AS2uN1C~N>&=eDPwE0M1Q&!51npP5^&=$w5ojIT|E z`sCapF9DqY_0 z+J|C!i9BebTjc0EMs#dhkT|H*HdVFr3qr0yEoCT-l&?ra>O#pQXH}u1CnGm{ZR#upDJd zAPX%9211iOc{)tQg^rKrimI7*G0K8b0H%eSJuz4R{c!3Df9z-(?jPmPNWh7eUc%AtWtvpeHm= z)d4#RUVIebD|nSnlKm`D8_XNQu|T16f-CC|w8w@32%HSnX%!3T+1sU?sB+R+~g}N)wvhE_5HY3Wvi3>K5JK!&P>kH!4c@j{x84Y3h8GeDB zP=mU;AbI8p7680=3~K8A?@~?0dB>pgZzebeb(w8yKMPESo@ zz}%N0bFE#}vP(EFZElOj-3oJn8Bp#5s+Reocq3Jgf{KYk2i&`^_lB%q3{cb;14Mv@ zoOe&GUR}WgcJ*=<2C%Ew|1iQ`y`YK_Zuk{yRXozXLhTek0iyL+sQoX%0DJn9yuv^) QjsO4v07*qoM6N<$g5oNn-~a#s literal 0 HcmV?d00001 diff --git a/src/assets/img/dgb.png b/src/assets/img/dgb.png new file mode 100644 index 0000000000000000000000000000000000000000..6950158b56d73dcce67b8fece5cc1d1817b6b51c GIT binary patch literal 4917 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 literal 0 HcmV?d00001 diff --git a/src/assets/img/doge.png b/src/assets/img/doge.png new file mode 100644 index 0000000000000000000000000000000000000000..d99fa2ff2a6b1c969c23a22d9d265fa2c872a9ac GIT binary patch literal 1798 zcmV+h2l@DkP)m>denkSs zAba6f4~k2CXk5I&G6xDlBEQ&Qgdo#_?Sf#Xq6CVgH3E4OC`*PgSSHzlhGEq9Di9{X zWA@@}C_GR&5TuoZd5qjV1dV+VUrS+39-FvS1ksyEHsH$D1!!`F>BQBEXfOf3CJ(+w z{u+u;Bq`j)X^R3^wgrJkg(>S-rEE1-qrzkhmCEFC0P-jxS?5^^y*5u)N{`w^RzVB5G)_FlEmER%=`PrI@wu?G;X^=#>R3f_A0^2~DZ)x!2C> z8yp`;@}Z^48rmaju2cJbrxAh;aro+%F zZ`@d4{vYhkAG^WE+7i_<4bD&27!SiG4A8Bv#ljeb`XLomZP{KUV=a9G6nB+`iSE(x z6qp$Klxp9q#*;zD(cXkK)CmL=q^WY5LSl)kEvsaCYNtjNb5EAJ$*-wQpK%k#C8UPN z1C@VrfViK@cErckTf+&% zQ>A(f$v^HidMElvn)+W6Kxb~8O9@Km>Q{X_0#KS@Lo0hIfYP@7XiYvMvI!c@P5C@s z1OfGk477p(G`4h?Wi9VPK)u4kG&K=@=*DW8WnlIS4b;}yPTc2#f7rkps3c_iQffdM z1#!R7{56)fyd0=v5Y%p zVa)#N7rQ~@VY-`izT4+*EX_T!^i(`h)ZjqRgw`MGrrJLmnGP^EcWJ9qLbDo12HH@9 zuc&4-3Oq(zYfg{jOpl&rshyGd%#g&=6aAvISj;vf#4-b{ewrc7N@CKUN&cB03Pu*L zvwXJca=Kc+uULT6nr$w!x)KP^dit!4zqT*2mIv7EJ)%YXbZOF`KcBX;Y=+?I?nwcf zOj<;kH?DT-7zd&hX4`<`wTyhC!CZ~bheofw#{;G>dHpA$XMw~6(AW>}@8dKXEQM93 znRKXO!eurHubFfyO^uMWFZ-L?gE^qCi0ZE*!{r5?DysKcP<$r zNE_$Vb*1~I+-zi&TQOhQiq+&1|2yZCj9+5J-Mgy_cW;hN+Bi?AdDfwAD>0I zCWX7$us|t9(7Gu)5)9fWNNJJB(GWl>$RvUsB5EazVAH+?iXc;TbQ8TK57#9N ztZ<+dB>2U&h9I55CMj4`OQ0C70pvLGmnAbZlDzAG(9{b zjUjUsYElVMG;vdd=q)1~i1WGtE})oGF8Uzw)Dy50Jh`iDpa|3SvA=ZVSL1G>x&j&? znA}jAfd&vJ7gQ#o7=Sh!*k`i%)F?}!G8jM53@}WBzn!U~G8nWo-GHePj|^eX&2REp z0WE|qOXPO7imD<|^qaW=1|gOp)leni0gA!GC5VIpJs~k*lG7XMFP!i zJKN&=yv)}fWvLXhs;QwV6<0UhAK^N0T^&$IR)!ARS=3Osvitso9m3nC-1Cr1#P}znc4L^@I#hH8ig3O2%S6eoU8~B(4Qep6Cwc=GM1e zJ%M6ZNm;*hn4{dxY-*>S#c1CN8X8q~1(EaZx-__L(sPmzHm%F&y zb(PN1BriSjp-K{ZUjJFi4eb2d*CN3;l$kqc|I@h){h>{mZwR0|m7&clz7!&Ky#n2) zl}w(z`|w4ps>w5;kS~JYoVYQ_mCP4qbv;ksuWgZ)^}LpueX|#)eLoSa+r%L)dh+U{ z>PH^xedq+OVnp~$&`8~3dIFRudG}fUUIw%v)7*KIcc%cPVY|*r3IJ5vqS9eOsS!kT zpU4IP-IJ-IR^gq8@c0>pWmD<&S#lQ#?NzE9k10fn^5q~n?BPi|{H zb281)s$FBTE3Q8WZipszI*XXivNRMR*g^Pgb{(G&#hJKS+26$5uJe((XMtt0QUbG= z`k;w4 z+z5*;2#MVYE5K0YZPgY)sPZ=xv_TEGyA%Z!p@ti>iUeu_o2G|*4FYq9f~;%bfN)c5 zOF5~zj2~H$H?da0000|H@`8$}eJETAGPXj)W25R?Ukkb0?o>#feEH&j>ZjYC{+oG`zj+g}jp#Eota zy;VvgZoPDK>n+ZKNC>sqA|RlG+EhhU2*P~ZnP9uS_Uz1?nT@qiS~*_N&c6Nf=Dj!H zyxmOGX0pw+NykuJdOOhP~gi*V948deV=bpF*|A2Bu zI{ahPVdS|i#QPO|PN@24C7cI;P^qL!*`p{~IUUweslF22PsfAH#fj&uJpYw!Hb zdVl;~N=sD&R0N=|i)4NA#0#ulKf|tHI6Jl7je8GSXZLqDc>0g4NkB~{P^k|2#08kG zbBpQFo&_cZZF--6m>%OmmIVgp7AkVHRoi|t;s9M-dPVE_or6DF#4R>Ccw!sab#A3? zZ9v8BVbi9c1dyvlR<^M}NP)HNU$0E#S#tpuezRvQ2m#1;{dIQgL_pf_@aezYxBiv_ zYcWWLdH!_T)xI(cT(yZ>ozo@%j$)f&(Db`7r2E~`&X1hFky9N`2bK>040lE-MtYo2rX}?KvM&y&x zg*U7WZC(Ew-TO7oUy0<}B=esIXwNj~L>dH(Smsf@jMC>>K|)}u7X02Om~Zw&l8 zPh$Y2PCC;O$F9?*LRtncS52jbHhgG-DEl4<1HQ|I*Tk{t1AU=SPtx!PDE#CV?gtyU zdrBz_BCtvnMqlU?efQll`eT4Du(fZ%Dm~Keg-185Oc1h&ND$6Au1FNtVYK+rH39WB z05u{)iU4~0%Wsv3b{^?mluU+YKlqK~pz=)9NI zI8E?_3IkfH0IdM60IdM6qyn@8be;hnRxpss5P)`lYXM5nguleG=%WPE1)u}pT5R2a ze6&nlWPJ#2kn*;M&Ul*!a@J;+=i!an?l zHjcSY6-k_0Xc7Jr<%d`wy2gQnkHm(*vCl$jBAE|OD@PVO``UNK6iwJAbb2gHJOJdF8__-FE>AamnB!jv=CRt4U}+rKR4V*6Z^!62C^8|uvjZS zwgim*|A30S8oVX=pV!Z%{uKqfMWuaotXIZh&?#zHxYVN)?F>Q%MQJPU=isLm>jVe`li7eZ0gtBO&O6BUv5Z#4b_PsMTa6fs#(uR5iKFD_blZy;kcA}tFYOoj)L5TK2SiV3_hsM%L4(yxH$dR32Ts%rh8_dFh`U2Hs zdSv%uf+F&FUHMdx($@h~%R)yiwR#{cC7>g~f*@F(6EJ5!ip@Hp0#w}E93Nx9IutV? z<8?I>)>bGIQWGkU1UiRQ?+vM53{ch=17rXTVkKhLt1GMkTfJPx0 txTCL73&mFC6>0)ZFgHh+XWI*A(+)*H2Pr02S_y9H;q2nn5YxCa+3PzDjTu9%eSn>fgNpp|wG zHjtJ;Imi~axgfP9g2!bQSkr+rkmwf!DF{*yY!d?;Oi7?TS|iA(A-$xHgEb{PaF`gi z!)XW;_%Vn1cc2H#4y2Xc9I!ERTOoMt2iSKBkeNI;@n8x>Z!59^f1)nHkswSTuTmBo zOyJ)s#J{8U8p{7sFwIR|Z&BbkS`auEVXFGopixcLt)Zy^^Qp&u@YtgdLT08Dsw+z& zcX<|!j!nX=uLq!`vo9qyRToemfI<|>dT#DA*tN3(c0Jo507NU%?ShL)x!Y_fBEf~FGpdbTz*5HlV4}MOBi?=4oGirTShmP9Zc0m(I4V4PQT~l5Nz<&RAwX4Bf zT?UcJAY8vb0w+#(!lrt+?7r}G=n9@>0Zr*W1|`7R$cj_#gH#b615jD%y?>3S?Q}Z8 zwYC_tvYfD<0YzEv$`X9&z`!l$4kD13mmT9CEHe87&Zbef$@3Q65vug)aN8cie0#6l z01wl|Jvg$gFZz{ovzdy<*^%_vBG+}Sk%cc-SI#+ywvomv{Nq0N-qdFSpF z+!>pKr7WUXtSN%hmH7$n3sWi!%TSPE7MQ1@y!k=a->hO4&cx(hxHU2X;qE~={#PfQ zJ=Y`nNuy%3+1E=uQqEM+PBc;f_VwWPl*vZ&GiM{PWQhYV_uha!mhewc&p;t7GfRr| zWAat0w%hHk*wz#ew2{o*nQxq7`S8V#KBissUHC?xKGkignD-i%mQyn`(Dm;?w4LXw zD7O16G{z+Mlr=lbyKgo^rMrar%|g}0-H2daBXlT;e8I@x*fgW*FS7_`%cyD5vZFIsI*L!M)+hPOioV4bffInP&Xw^sYzm_ zj|LT1yJJ%%p#s}=FAv2AvyDRQL$T(L7mW0xV4|OhWJr7{g@zWSg1Jj0y(s17_ZhC` z@%`f99#&DKqZ4+1r2+>Kid@Ydjr2^g+k_>h5s7r))9~NzHFrTsfl7yo<0HK&`T5z# zG*qIIXY4h1TA)fDq4-+fy|y?eQP&cj_eA7BX@M&BETxfNE>YK#+v9US7iW)92pLeh z2rn1u#S|+3IVCA7$|KWGQlM(%KGH}ZeQso2Um}>FGY2&EKLU!)3b{_ZT%;ETCxPME zyP9B`iTlM{8^@I90Ub^y?Ual3Vw0oy>P^+pjqnIhW$wrlfrjk09C4@k2Kfl~lt*)W6kzPllpOc+Mt)XEO4HXC7R4X2ZsIHdiM!VWPt`# z$$zRvdNI*IezH^cH5^VM)J~M3?Hant=hpQ;xkxWc_OeXb=W+O$7--1B&unNd?F|bX1p|rJVs~54M|2X<)p@29!>N!GJveyl(LfoZB3O3FUshM`tSuN`r@?lirf(X1x%x}II^=dHQ%#g-D>#k^Ft)#M{>;O zou{;Q$6oa8rq8p-nQ-sCp?{4RY{7l>$wBHwU9&=F+8N`=EJ74sv;%rRMb$e zr9)~TG*oiRbm%eg?0l{@-CzoerndHoYUa%A(|u+}cp>nxyzwojnKn=4GDE)6S~XYi zsyGR+B8Ef8KYjOFx(1&3ib!+nr&H(7{E*->L!x$K;Av$kQJP8wbWWYOd?74c?g9tR zhEVGi4pzgw0!n&Z&6N3}{6O4hHdO3vbl|a@b={D~3j?I; zg#l#1Vq>KR7B5|43E0Jpt5^Vb@$x?w!d<*Tm4$Gnmr!%_&B!IxhWIT)B)^2(e*z2u Xq@DHT-WO?J00000NkvXXu0mjfNJg50 literal 0 HcmV?d00001 diff --git a/src/components/Grids/OngoingTrades.tsx b/src/components/Grids/OngoingTrades.tsx index 5a62d42..b3f93a4 100644 --- a/src/components/Grids/OngoingTrades.tsx +++ b/src/components/Grids/OngoingTrades.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { AgGridReact } from 'ag-grid-react'; -import { ColDef, SizeColumnsToContentStrategy } from 'ag-grid-community'; +import { ColDef, RowClassParams, RowStyle, SizeColumnsToContentStrategy } from 'ag-grid-community'; import 'ag-grid-community/styles/ag-grid.css'; import 'ag-grid-community/styles/ag-theme-alpine.css'; import gameContext from '../../contexts/gameContext'; @@ -10,9 +10,17 @@ const autoSizeStrategy: SizeColumnsToContentStrategy = { }; export const OngoingTrades = () => { - const { onGoingTrades } = useContext(gameContext); - + const { onGoingTrades, getCoinLabel, selectedCoin } = useContext(gameContext); + const gridRef = useRef(null) + + + const onGridReady = useCallback((params: any) => { + // params.api.sizeColumnsToFit(); // Adjust columns to fit the grid width + // const allColumnIds = params.columnApi.getAllColumns().map((col: any) => col.getColId()); + // params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content + }, []); + const defaultColDef = { resizable: true, // Make columns resizable by default sortable: true, // Make columns sortable by default @@ -35,9 +43,10 @@ export const OngoingTrades = () => { resizable: true , flex: 1, minWidth: 100 }, - { headerName: "Amount (QORT)", valueGetter: (params) => +params.data.tradeInfo.qortAmount, resizable: true, flex: 1, minWidth: 100 }, - { headerName: "LTC/QORT", valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount / +params.data.tradeInfo.qortAmount , resizable: true , flex: 1, minWidth: 100}, - { headerName: "Total LTC Value", valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount, resizable: true , flex: 1, minWidth: 100 }, + { headerName: "Amount (QORT)", valueGetter: (params) => +params.data.tradeInfo.qortAmount, resizable: true, flex: 1, minWidth: 150 }, + { headerName: `${getCoinLabel()}/QORT`, valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount / +params.data.tradeInfo.qortAmount , resizable: true , flex: 1, minWidth: 150}, + { headerName: `Total ${getCoinLabel()} Value`, valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount, resizable: true , flex: 1, minWidth: 150, + }, { headerName: "Notes", valueGetter: (params) => { if (params.data.tradeInfo.mode === 'TRADING') { @@ -54,7 +63,7 @@ export const OngoingTrades = () => { } if (params.data.message) return params.data.message - }, resizable: true, flex: 1, minWidth: 100 + }, resizable: true, flex: 1, minWidth:300, autoHeight: true, cellStyle: { whiteSpace: 'normal', wordBreak: 'break-word', padding: '5px' }, } ]; @@ -65,15 +74,20 @@ export const OngoingTrades = () => { // return null; // }; const getRowId = useCallback(function (params: any) { - return String(params.data._id); + return String(params.data?.qortalAtAddress); }, []); + + return (
item?.tradeInfo?.foreignBlockchain === selectedCoin)} // onRowClicked={onRowClicked} rowSelection="single" getRowId={getRowId} @@ -85,7 +99,7 @@ export const OngoingTrades = () => { // domLayout='autoHeight' // getRowStyle={getRowStyle} - + />
); diff --git a/src/components/Grids/TradeOffers.tsx b/src/components/Grids/TradeOffers.tsx index bd9797f..bdd5721 100644 --- a/src/components/Grids/TradeOffers.tsx +++ b/src/components/Grids/TradeOffers.tsx @@ -11,6 +11,9 @@ import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events'; import { useModal } from '../common/useModal'; import FileSaver from 'file-saver'; +// export const baseLocalHost = window.location.host +export const baseLocalHost = '127.0.0.1:12391' + interface RowData { amountQORT: number; priceUSD: number; @@ -32,10 +35,10 @@ export const autoSizeStrategy: SizeColumnsToContentStrategy = { type: 'fitCellContents' }; -export const TradeOffers: React.FC = ({ltcBalance}:any) => { +export const TradeOffers: React.FC = ({foreignCoinBalance}:any) => { const [offers, setOffers] = useState([]) - - const { fetchOngoingTransactions, onGoingTrades, updateTransactionInDB, isUsingGateway } = useContext(gameContext); + const [qortalNames, setQortalNames] = useState({}) + const { fetchOngoingTransactions, onGoingTrades, updateTransactionInDB, isUsingGateway, getCoinLabel, selectedCoin } = useContext(gameContext); const listOfOngoingTradesAts = useMemo(()=> { return onGoingTrades?.filter((item)=> item?.status !== 'trade-failed')?.map((trade)=> trade?.qortalAtAddress) || [] }, [onGoingTrades]) @@ -50,7 +53,7 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { const offersWithoutOngoing = useMemo(()=> { return offers.filter((item)=> !listOfOngoingTradesAts.includes(item.qortalAtAddress)) }, [listOfOngoingTradesAts, offers]) - + const initiatedFetchPresence = useRef(false) const [selectedOffer, setSelectedOffer] = useState(null) @@ -80,6 +83,30 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { suppressMovable: true, // Prevent columns from being movable }; + const getName = async (address)=> { + try { + const response = await fetch("/names/address/" + address); + const nameData = await response.json(); + if (nameData?.length > 0) { + setQortalNames((prev)=> { + return { + ...prev, + [address]: nameData[0].name + } + }) + } else { + setQortalNames((prev)=> { + return { + ...prev, + [address]: null + } + }) + } + } catch (error) { + // error + } + } + const columnDefs: ColDef[] = [ { headerCheckboxSelection: true, // Adds a checkbox in the header for selecting all rows @@ -92,15 +119,28 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { { headerName: "QORT AMOUNT", field: "qortAmount" , flex: 1, // Flex makes this column responsive minWidth: 150, // Ensure it doesn't shrink too much resizable: true }, - { headerName: "LTC/QORT", valueGetter: (params) => +params.data.foreignAmount / +params.data.qortAmount, sortable: true, sort: 'asc', flex: 1, // Flex makes this column responsive + { headerName: `${getCoinLabel()}/QORT`, valueGetter: (params) => +params.data.foreignAmount / +params.data.qortAmount, sortable: true, sort: 'asc', flex: 1, // Flex makes this column responsive minWidth: 150, // Ensure it doesn't shrink too much resizable: true }, - { headerName: "Total LTC Value", field: "foreignAmount", flex: 1, // Flex makes this column responsive + { headerName: `Total ${getCoinLabel()} Value`, field: "foreignAmount", flex: 1, // Flex makes this column responsive minWidth: 150, // Ensure it doesn't shrink too much resizable: true }, { headerName: "Seller", field: "qortalCreator", flex: 1, // Flex makes this column responsive minWidth: 300, // Ensure it doesn't shrink too much - resizable: true }, + resizable: true, valueGetter: (params)=> { + if(params?.data?.qortalCreator){ + if(qortalNames[params?.data?.qortalCreator]){ + return qortalNames[params?.data?.qortalCreator] + } else if(qortalNames[params?.data?.qortalCreator] === undefined){ + getName(params?.data?.qortalCreator) + + return params?.data?.qortalCreator + } else { + return params?.data?.qortalCreator + + } + } + } }, ]; @@ -225,7 +265,7 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { if(isUsingGateway){ socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradepresence` } else { - socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradepresence`; + socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradepresence`; } @@ -245,44 +285,59 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { } socket.onerror = (e) => { clearTimeout(socketTimeout) + restartTradePresenceWebSocket() } const pingSocket = () => { socket.send('ping') socketTimeout = setTimeout(pingSocket, 295000) } } + const socketRef = useRef(null) + + const restartTradeOffers = ()=> { + if (socketRef.current) { + socketRef.current.close(1000, 'forced'); // Close with a custom reason + socketRef.current = null + } + offeringTrades.current = [] + setOffers([]) + setSelectedOffer(null) + } const initTradeOffersWebSocket = (restarted = false) => { - let tradeOffersSocketCounter = 0 + + if(socketRef.current) return let socketTimeout: any let socketLink if(isUsingGateway){ - socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradeoffers?foreignBlockchain=LITECOIN&includeHistoric=true` + socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradeoffers?foreignBlockchain=${selectedCoin}&includeHistoric=true` } else { - socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradeoffers?foreignBlockchain=LITECOIN&includeHistoric=true` + socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradeoffers?foreignBlockchain=${selectedCoin}&includeHistoric=true` } - const socket = new WebSocket(socketLink) - socket.onopen = () => { + socketRef.current = new WebSocket(socketLink) + socketRef.current.onopen = () => { setTimeout(pingSocket, 50) - tradeOffersSocketCounter += 1 } - socket.onmessage = (e) => { - offeringTrades.current = [...offeringTrades.current, ...JSON.parse(e.data)] - tradeOffersSocketCounter += 1 + socketRef.current.onmessage = (e) => { + offeringTrades.current = [...offeringTrades.current?.filter((coin)=> coin?.foreignBlockchain === selectedCoin), ...JSON.parse(e.data)?.filter((coin)=> coin?.foreignBlockchain === selectedCoin)] restarted = false processOffersWithPresence() } - socket.onclose = () => { + socketRef.current.onclose = (event) => { clearTimeout(socketTimeout) + if (event.reason === 'forced') { + return + } restartTradeOffersWebSocket() + socketRef.current = null } - socket.onerror = (e) => { + socketRef.current.onerror = (e) => { clearTimeout(socketTimeout) } const pingSocket = () => { - socket.send('ping') + socketRef.current.send('ping') socketTimeout = setTimeout(pingSocket, 295000) } } @@ -290,8 +345,11 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { useEffect(() => { blockedTradesList.current = JSON.parse(localStorage.getItem('failedTrades') || '[]') - initTradePresenceWebSocket() - initTradeOffersWebSocket() + if(!initiatedFetchPresence.current){ + initiatedFetchPresence.current = true + initTradePresenceWebSocket() + + } getNewBlockedTrades() const intervalBlockTrades = setInterval(() => { getNewBlockedTrades() @@ -302,6 +360,24 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { } }, [isUsingGateway]) + + + useEffect(() => { + if(selectedCoin === null) return + restartTradeOffers() + setTimeout(() => { + initTradeOffersWebSocket() + + }, 500); + return () => { + if(socketRef.current){ + socketRef.current.close(1000, 'forced'); + } + } + }, [isUsingGateway, selectedCoin]) + + + const selectedTotalLTC = useMemo(() => { @@ -313,11 +389,11 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { const buyOrder = async () => { try { - if(+ltcBalance < +selectedTotalLTC.toFixed(4)){ + if(+foreignCoinBalance < +selectedTotalLTC.toFixed(4)){ setOpen(true) setInfo({ type: 'error', - message: "You don't have enough LTC or your balance was not retrieved" + message: `You don't have enough ${getCoinLabel()} or your balance was not retrieved` }) return } @@ -329,11 +405,10 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { message: "Attempting to submit buy order. Please wait..." }) const listOfATs = selectedOffers - const response = await qortalRequestWithTimeout({ action: "CREATE_TRADE_BUY_ORDER", crosschainAtInfo: listOfATs, - foreignBlockchain: 'LITECOIN' + foreignBlockchain: selectedCoin }, 900000); if(response?.error){ @@ -381,7 +456,7 @@ export const TradeOffers: React.FC = ({ltcBalance}:any) => { setOpen(true) setInfo({ type: 'error', - message: error?.message || "Failed to submit trade order." + message: error?.error || error?.message || "Failed to submit trade order." }) console.error(error) } @@ -471,7 +546,7 @@ const handleClose = ( onSelectionChanged={onSelectionChanged} getRowStyle={getRowStyle} autoSizeStrategy={autoSizeStrategy} - rowSelection="multiple" // Enable multi-select + rowSelection={selectedCoin === 'PIRATECHAIN' ? "single" :"multiple"} // Enable multi-select rowMultiSelectWithClick={true} suppressHorizontalScroll={false} // Allow horizontal scroll on mobile if needed suppressCellFocus={true} // Prevents cells from stealing focus in mobile @@ -486,6 +561,9 @@ const handleClose = ( )} */} +
ltcBalance ? 'red' : 'white', + color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white', }}>{selectedTotalLTC?.toFixed(4)} LTC + }}>{`${getCoinLabel()} `} @@ -528,9 +606,9 @@ const handleClose = ( fontSize: '16px', color: 'white', - }}>{ltcBalance?.toFixed(4)} {foreignCoinBalance?.toFixed(4)} LTC balance + }}>{`${getCoinLabel()} `} balance {BuyButton()} diff --git a/src/components/Terms.tsx b/src/components/Terms.tsx index ddba254..3ab87f2 100644 --- a/src/components/Terms.tsx +++ b/src/components/Terms.tsx @@ -55,14 +55,14 @@ export const Terms =() => { - The purpose of q-trade is to make trading LTC for QORT as easy as possible. The maintainers of this site do not profit from its use—there are no additional fees for buying QORT through this site. There are two ways to place a buy order: + The purpose of q-trade is to make trading LTC and other coins for QORT as easy as possible. The maintainers of this site do not profit from its use—there are no additional fees for buying QORT through this site. There are two ways to place a buy order: 1. Use the gateway 2. Use your local node. By using q-trade, you agree to the following terms and conditions. - Using the gateway means you trust the maintainer of the node, as your LTC private key will need to be handled by that node to execute a trade order. If you have more than 4 QORT and your public key is already on the blockchain, your LTC private key will be transmitted using q-chat. If not, the message will be encrypted in the same manner as q-chat but stored temporarily in a database to ensure it reaches its destination. + Using the gateway means you trust the maintainer of the node, as your foreign coin (i.e. LTC) private key will need to be handled by that node to execute a trade order. If you have more than 4 QORT and your public key is already on the blockchain, your foreign coin private key will be transmitted using q-chat. If not, the message will be encrypted in the same manner as q-chat but stored temporarily in a database to ensure it reaches its destination. @@ -70,7 +70,7 @@ export const Terms =() => { - The maintainers and devs of this site are not responsible for any lost LTC, QORT, or other cryptocurrencies that may result from using this site. This is a hobby project, and mistakes in the code may occur. Please proceed with caution. + The maintainers and devs of this site are not responsible for any lost foreign coin, QORT, or other cryptocurrencies that may result from using this site. This is a hobby project, and mistakes in the code may occur. diff --git a/src/components/header/Header.tsx b/src/components/header/Header.tsx index c74b2e5..7f5b829 100644 --- a/src/components/header/Header.tsx +++ b/src/components/header/Header.tsx @@ -36,6 +36,12 @@ import { } from "@mui/material"; import { sendRequestToExtension } from "../../App"; import { Terms } from "../Terms"; +import ltcIcon from '../../assets/img/ltc.png' +import btcIcon from '../../assets/img/btc.png' +import dogeIcon from '../../assets/img/doge.png' +import rvnIcon from '../../assets/img/rvn.png' +import dgbIcon from '../../assets/img/dgb.png' +import arrrIcon from '../../assets/img/arrr.png' const checkIfLocal = async () => { try { @@ -59,7 +65,47 @@ export const Label = styled("label")( ` ); -export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { +const SelectRow = ({coin})=> { + let img + switch (coin) { + case 'LTC': + img = ltcIcon + break; + case 'BTC': + img = btcIcon + break; + + case 'DOGE': + img = dogeIcon + break; + case 'RVN': + img = rvnIcon + break; + + case 'ARRR': + img = arrrIcon + break; + case 'DGB': + img = dgbIcon + break; + default: + null + } + + return ( +

{coin}

+ ) +} + +export const Header = ({ qortBalance, foreignCoinBalance, mode, setMode }: any) => { const [openDropdown, setOpenDropdown] = useState(false); const dropdownRef = useRef(null); const buttonRef = useRef(null); @@ -67,7 +113,6 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { const [open, setOpen] = useState(false); const [info, setInfo] = useState(null); const { isUsingGateway } = useContext(gameContext); - const [selectedCoin, setSelectedCoin] = useState("LITECOIN"); const handleChange = (event: ChangeEvent) => { setChecked(false); @@ -77,7 +122,7 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { message: "Change the node you are using at the authentication page", }); }; - const { userInfo } = useContext(gameContext); + const { userInfo, selectedCoin, setSelectedCoin, getCoinLabel } = useContext(gameContext); const { avatar, setAvatar } = useContext(UserContext); const LocalNodeSwitch = styled(Switch)(({ theme }) => ({ @@ -185,7 +230,12 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { value={selectedCoin} onChange={(e) => setSelectedCoin(e.target.value)} > - LTC + + + + + + @@ -195,7 +245,7 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { }}> Balance: {qortBalance} QORT |{" "} - {ltcBalance === null ? "N/A" : ltcBalance} LTC + {foreignCoinBalance === null ? "N/A" : foreignCoinBalance} {getCoinLabel()} {userInfo?.name ? ( @@ -247,8 +297,20 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => { alignItems: "center", }} > - - + + { const [open, setOpen] = React.useState(false); const [qortAmount, setQortAmount] = React.useState(0) const [foreignAmount, setForeignAmount] = React.useState(0) - const {updateTemporaryFailedTradeBots, sellOrders, fetchTemporarySellOrders, isUsingGateway} = useContext(gameContext) + const {updateTemporaryFailedTradeBots, sellOrders, fetchTemporarySellOrders, isUsingGateway, getCoinLabel, selectedCoin} = useContext(gameContext) const [openAlert, setOpenAlert] = React.useState(false) const [info, setInfo] = React.useState(null) const handleClickOpen = () => { @@ -80,7 +100,6 @@ export const CreateSell = ({qortAddress, show}) => { const createSellOrder = async() => { try { - setOpen(true) setInfo({ type: 'info', message: "Attempting to create sell order. Please wait..." @@ -88,8 +107,8 @@ export const CreateSell = ({qortAddress, show}) => { const res = await qortalRequestWithTimeout({ action: "CREATE_TRADE_SELL_ORDER", qortAmount, - foreignBlockchain: 'LITECOIN', - foreignAmount + foreignBlockchain: selectedCoin, + foreignAmount: qortAmount * foreignAmount }, 900000); if(res?.error && res?.failedTradeBot){ @@ -167,7 +186,6 @@ export const CreateSell = ({qortAddress, show}) => {
) } - return (
{ }} > - New Sell Order - QORT for LTC + {`New Sell Order - QORT for ${getCoinLabel()}`} { /> - Price Each (LTC) + {`Price Each (${getCoinLabel()})`} { autoComplete="off" /> - {qortAmount * foreignAmount} LTC for {qortAmount} QORT + {`${qortAmount * foreignAmount} ${getCoinLabel()}`} for {qortAmount} QORT Total sell amount needs to be greater than: {minimumAmountSellTrades.LITECOIN.value} {' '} {minimumAmountSellTrades.LITECOIN.ticker} + }}>Total sell amount needs to be greater than: {minimumAmountSellTrades[selectedCoin]?.value} {' '} {minimumAmountSellTrades[selectedCoin]?.ticker} @@ -236,7 +254,7 @@ export const CreateSell = ({qortAddress, show}) => { - diff --git a/src/components/sell/TradeBotList.tsx b/src/components/sell/TradeBotList.tsx index 8bc86ff..c317868 100644 --- a/src/components/sell/TradeBotList.tsx +++ b/src/components/sell/TradeBotList.tsx @@ -8,7 +8,7 @@ import React, { useRef, useState, } from "react"; -import { autoSizeStrategy } from "../Grids/TradeOffers"; +import { autoSizeStrategy, baseLocalHost } from "../Grids/TradeOffers"; import { Alert, Box, Snackbar, SnackbarCloseReason, Typography } from "@mui/material"; import gameContext from "../../contexts/gameContext"; @@ -18,47 +18,47 @@ const defaultColDef = { suppressMovable: true, // Prevent columns from being movable }; -const columnDefs: ColDef[] = [ - { - headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows - checkboxSelection: true, // Adds checkboxes in each row for selection - headerName: "Select", // You can customize the header name - width: 50, // Adjust the width as needed - pinned: "left", // Optional, to pin this column on the left - resizable: false, - }, - { - headerName: "QORT AMOUNT", - field: "qortAmount", - flex: 1, // Flex makes this column responsive - minWidth: 150, // Ensure it doesn't shrink too much - resizable: true, - }, - { - headerName: "LTC/QORT", - valueGetter: (params) => - +params.data.foreignAmount / +params.data.qortAmount, - sortable: true, - sort: "asc", - flex: 1, // Flex makes this column responsive - minWidth: 150, // Ensure it doesn't shrink too much - resizable: true, - }, - { - headerName: "Total LTC Value", - field: "foreignAmount", - flex: 1, // Flex makes this column responsive - minWidth: 150, // Ensure it doesn't shrink too much - resizable: true, - }, - { - headerName: "Status", - field: "status", - flex: 1, // Flex makes this column responsive - minWidth: 300, // Ensure it doesn't shrink too much - resizable: true, - }, -]; +// const columnDefs: ColDef[] = [ +// { +// headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows +// checkboxSelection: true, // Adds checkboxes in each row for selection +// headerName: "Select", // You can customize the header name +// width: 50, // Adjust the width as needed +// pinned: "left", // Optional, to pin this column on the left +// resizable: false, +// }, +// { +// headerName: "QORT AMOUNT", +// field: "qortAmount", +// flex: 1, // Flex makes this column responsive +// minWidth: 150, // Ensure it doesn't shrink too much +// resizable: true, +// }, +// { +// headerName: "LTC/QORT", +// valueGetter: (params) => +// +params.data.foreignAmount / +params.data.qortAmount, +// sortable: true, +// sort: "asc", +// flex: 1, // Flex makes this column responsive +// minWidth: 150, // Ensure it doesn't shrink too much +// resizable: true, +// }, +// { +// headerName: "Total LTC Value", +// field: "foreignAmount", +// flex: 1, // Flex makes this column responsive +// minWidth: 150, // Ensure it doesn't shrink too much +// resizable: true, +// }, +// { +// headerName: "Status", +// field: "status", +// flex: 1, // Flex makes this column responsive +// minWidth: 300, // Ensure it doesn't shrink too much +// resizable: true, +// }, +// ]; export default function TradeBotList({ qortAddress, failedTradeBots }) { const [tradeBotList, setTradeBotList] = useState([]); @@ -67,7 +67,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { const offeringTrades = useRef([]); const qortAddressRef = useRef(null); const gridRef = useRef(null); - const {updateTemporaryFailedTradeBots, fetchTemporarySellOrders, deleteTemporarySellOrder} = useContext(gameContext) + const {updateTemporaryFailedTradeBots, fetchTemporarySellOrders, deleteTemporarySellOrder, getCoinLabel, selectedCoin} = useContext(gameContext) const [open, setOpen] = useState(false) const [info, setInfo] = useState(null) const filteredOutTradeBotListWithoutFailed = useMemo(() => { @@ -88,6 +88,51 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content }, []); + + const columnDefs: ColDef[] = useMemo(()=> { + return [ + { + headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows + checkboxSelection: true, // Adds checkboxes in each row for selection + headerName: "Select", // You can customize the header name + width: 50, // Adjust the width as needed + pinned: "left", // Optional, to pin this column on the left + resizable: false, + }, + { + headerName: "QORT AMOUNT", + field: "qortAmount", + flex: 1, // Flex makes this column responsive + minWidth: 150, // Ensure it doesn't shrink too much + resizable: true, + }, + { + headerName: `${getCoinLabel()}/QORT`, + valueGetter: (params) => + +params.data.foreignAmount / +params.data.qortAmount, + sortable: true, + sort: "asc", + flex: 1, // Flex makes this column responsive + minWidth: 150, // Ensure it doesn't shrink too much + resizable: true, + }, + { + headerName: `Total ${getCoinLabel()} Value`, + field: "foreignAmount", + flex: 1, // Flex makes this column responsive + minWidth: 150, // Ensure it doesn't shrink too much + resizable: true, + }, + { + headerName: "Status", + field: "status", + flex: 1, // Flex makes this column responsive + minWidth: 300, // Ensure it doesn't shrink too much + resizable: true, + }, + ]; + + }, [selectedCoin]) useEffect(() => { if (qortAddress) { qortAddressRef.current = qortAddress; @@ -154,38 +199,64 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { tradeBotListRef.current = sellTrades; }; + const restartTradeOffers = ()=> { + if (socketRef.current) { + socketRef.current.close(1000, 'forced'); // Close with a custom reason + socketRef.current = null + } + offeringTrades.current = [] + setTradeBotList([]); + tradeBotListRef.current = []; + } + + const socketRef = useRef(null) + const initTradeOffersWebSocket = (restarted = false) => { let tradeOffersSocketCounter = 0; let socketTimeout: any; // let socketLink = `ws://127.0.0.1:12391/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`; - let socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`; - const socket = new WebSocket(socketLink); - socket.onopen = () => { + let socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradebot?foreignBlockchain=${selectedCoin}`; + socketRef.current = new WebSocket(socketLink); + socketRef.current.onopen = () => { setTimeout(pingSocket, 50); tradeOffersSocketCounter += 1; }; - socket.onmessage = (e) => { + socketRef.current.onmessage = (e) => { tradeOffersSocketCounter += 1; restarted = false; processTradeBots(JSON.parse(e.data)); }; - socket.onclose = () => { + socketRef.current.onclose = (event) => { clearTimeout(socketTimeout); + if (event.reason === 'forced') { + return + } restartTradeOffersWebSocket(); }; - socket.onerror = (e) => { + socketRef.current.onerror = (e) => { clearTimeout(socketTimeout); }; const pingSocket = () => { - socket.send("ping"); + socketRef.current.send("ping"); socketTimeout = setTimeout(pingSocket, 295000); }; }; useEffect(() => { if(!qortAddress) return - initTradeOffersWebSocket(); - }, [qortAddress]); + if(selectedCoin === null) return + restartTradeOffers() + + setTimeout(() => { + initTradeOffersWebSocket() + + }, 500); + return () => { + if(socketRef.current){ + socketRef.current.close(1000, 'forced'); + } + } + }, [qortAddress, selectedCoin]); const onSelectionChanged = (event: any) => { const selectedRows = event.api.getSelectedRows(); @@ -222,7 +293,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { const res = await qortalRequestWithTimeout({ action: "CANCEL_TRADE_SELL_ORDER", qortAmount: selectedTrade.qortAmount, - foreignBlockchain: 'LITECOIN', + foreignBlockchain: selectedTrade.foreignBlockchain, foreignAmount: selectedTrade.foreignAmount, atAddress: selectedTrade.atAddress }, 900000); @@ -329,7 +400,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { }}> {/* ltcBalance ? 'red' : 'white', + color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white', }}>{selectedTotalLTC?.toFixed(4)} LTC */} @@ -340,7 +411,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) { fontSize: '16px', color: 'white', - }}>{ltcBalance?.toFixed(4)} {foreignCoinBalance?.toFixed(4)} LTC balance */} diff --git a/src/contexts/gameContext.ts b/src/contexts/gameContext.ts index 487a536..ab2d9dd 100644 --- a/src/contexts/gameContext.ts +++ b/src/contexts/gameContext.ts @@ -14,7 +14,7 @@ export interface UserNameAvatar { } export interface IContextProps { - ltcBalance: number | null; + foreignCoinBalance: number | null; qortBalance: number | null; userInfo: any; setUserInfo: (val: any) => void; @@ -32,11 +32,14 @@ export interface IContextProps { updateTemporaryFailedTradeBots: (val: any)=> void; fetchTemporarySellOrders: ()=> void; isUsingGateway: boolean; + selectedCoin: string; + setSelectedCoin: (val: any)=> void; + getCoinLabel: ()=> void; } const defaultState: IContextProps = { qortBalance: null, - ltcBalance: null, + foreignCoinBalance: null, userInfo: null, setUserInfo: () => {}, userNameAvatar: {}, @@ -52,7 +55,10 @@ const defaultState: IContextProps = { deleteTemporarySellOrder: ()=> {}, updateTemporaryFailedTradeBots: ()=> {}, fetchTemporarySellOrders: ()=> {}, - isUsingGateway: true + isUsingGateway: true, + selectedCoin: 'LITECOIN', + setSelectedCoin: ()=> {}, + getCoinLabel: ()=> {} }; export default React.createContext(defaultState); diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx index e639164..14570c5 100644 --- a/src/pages/Home/Home.tsx +++ b/src/pages/Home/Home.tsx @@ -24,7 +24,7 @@ export const HomePage: FC = ({}) => { const navigate = useNavigate(); const { qortBalance, - ltcBalance, + foreignCoinBalance, userInfo, isAuthenticated, setIsAuthenticated, @@ -53,7 +53,7 @@ export const HomePage: FC = ({}) => {
@@ -97,7 +97,7 @@ export const HomePage: FC = ({}) => { - +