From 124fdb07caebeb95266eaf4f796018e09132c491 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Mon, 11 Mar 2019 16:25:54 +0100 Subject: [PATCH 01/31] watch asset wip --- src/modules/watchAsset.js | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/modules/watchAsset.js diff --git a/src/modules/watchAsset.js b/src/modules/watchAsset.js new file mode 100644 index 00000000..af60eb0d --- /dev/null +++ b/src/modules/watchAsset.js @@ -0,0 +1,40 @@ +// WIP +import store from "modules/store"; + +export const watchAsset = () => { + const augmint = store.getState().augmintToken.info; + const etherProvider = store.getState().web3Connect.ethers.provider; + // const user = store.getState().userBalances + const contracts = store.getState().contracts; + + const tokenType = "ERC20"; + const image = "http://placekitten.com/200/300"; + const id = Math.round(Math.random() * 100000); // TODO + + if (augmint.symbol && augmint.decimals && contracts) { + const options = { + address: contracts.latest.augmintToken.address, + symbol: augmint.symbol, + decimals: augmint.decimals, + image: image + }; + + etherProvider._sendAsync( + { + method: "wallet_watchAsset", + params: { + type: tokenType, + options: options + }, + id: id + }, + (err, added) => { + if (added) { + console.log("ADDED", added); + } else { + console.log("ERR NOT ADDED"); + } + } + ); + } +}; From 22712e01e77f2350e45ae3d29289576cc75ebe78 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Tue, 12 Mar 2019 16:57:04 +0100 Subject: [PATCH 02/31] nav buttons for add asset metamask --- public/augmint-token-image.png | Bin 0 -> 2632 bytes src/components/accountInfo/index.js | 25 +++++++++ src/components/augmint-ui/icon/index.js | 3 ++ .../dashboard/containers/topNav/index.js | 25 +++++++++ .../dashboard/containers/topNav/styles.js | 6 ++- src/modules/watchAsset.js | 51 +++++++++--------- 6 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 public/augmint-token-image.png diff --git a/public/augmint-token-image.png b/public/augmint-token-image.png new file mode 100644 index 0000000000000000000000000000000000000000..4a7f1711b93402fb983c21c40badafb05959ecf1 GIT binary patch literal 2632 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 {data.web3Connect.network.name} + + {isMetamask && data.account.tokenBalance && ( + { + e.preventDefault(); + watchAsset(); + }} + className="addAsset" + > + + Add Augmint token to wallet + + )} {showMyAccountLink && More details} ); diff --git a/src/components/augmint-ui/icon/index.js b/src/components/augmint-ui/icon/index.js index 818593e9..ce1d5a48 100644 --- a/src/components/augmint-ui/icon/index.js +++ b/src/components/augmint-ui/icon/index.js @@ -70,6 +70,9 @@ export default function Icon(props) { case "empty": className += " empty"; break; + case "plus": + className += " fa fa-plus"; + break; default: break; } diff --git a/src/components/dashboard/containers/topNav/index.js b/src/components/dashboard/containers/topNav/index.js index cd72a66c..0bd88a78 100644 --- a/src/components/dashboard/containers/topNav/index.js +++ b/src/components/dashboard/containers/topNav/index.js @@ -2,6 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import store from "modules/store"; import { dismissTx } from "modules/reducers/submittedTransactions"; +import { watchAsset } from "modules/watchAsset.js"; import augmintTokenProvider from "modules/augmintTokenProvider"; import ratesProvider from "modules/ratesProvider"; @@ -74,6 +75,13 @@ class TopNav extends React.Component { visibility: "hidden" }; + let isMetamask = null; + + if (accountInfoData.web3Connect.web3Instance) { + const metamask = accountInfoData.web3Connect.web3Instance.currentProvider._metamask; + isMetamask = metamask ? metamask.isEnabled() : null; + } + Object.keys(transactions).forEach(e => { if (transactions[e].event === "transactionHash" || transactions[e].event === "receipt") { notiIcon = "circle notched"; @@ -173,6 +181,23 @@ class TopNav extends React.Component { {this.props.web3Connect.network.name} + + {tokenBalance && isMetamask && ( + + { + e.preventDefault(); + watchAsset(); + }} + className="addAsset" + > + + Add asset + + + )} ); diff --git a/src/components/dashboard/containers/topNav/styles.js b/src/components/dashboard/containers/topNav/styles.js index 0389ef84..8302c6c0 100644 --- a/src/components/dashboard/containers/topNav/styles.js +++ b/src/components/dashboard/containers/topNav/styles.js @@ -134,6 +134,7 @@ export const StyledTopNavLinkRight = styled(StyledTopNavLink)` display: flex; flex-direction: column; font-size: 11px; + border-right: solid 1px #cccccc; &:not(.accountDetails) { &:not(.notifications) { @@ -151,11 +152,14 @@ export const StyledTopNavLinkRight = styled(StyledTopNavLink)` &.notifications { border-left: solid 1px #fff; - border-right: solid 1px #cccccc; :hover { border-right: solid 1px #fff; } } + + &.addAsset { + border-right: none; + } `; export const StyledPrice = styled.span` diff --git a/src/modules/watchAsset.js b/src/modules/watchAsset.js index af60eb0d..02d41789 100644 --- a/src/modules/watchAsset.js +++ b/src/modules/watchAsset.js @@ -1,40 +1,37 @@ -// WIP import store from "modules/store"; export const watchAsset = () => { const augmint = store.getState().augmintToken.info; - const etherProvider = store.getState().web3Connect.ethers.provider; - // const user = store.getState().userBalances + const currentProvider = store.getState().web3Connect.web3Instance.currentProvider; const contracts = store.getState().contracts; const tokenType = "ERC20"; - const image = "http://placekitten.com/200/300"; + const image = "https://www.augmint.org/apple-touch-icon.png"; // TODO const id = Math.round(Math.random() * 100000); // TODO - if (augmint.symbol && augmint.decimals && contracts) { - const options = { - address: contracts.latest.augmintToken.address, - symbol: augmint.symbol, - decimals: augmint.decimals, - image: image - }; + const method = "wallet_watchAsset"; + const options = { + address: contracts.latest.augmintToken.address, + symbol: augmint.symbol, + decimals: augmint.decimals, + image: image + }; - etherProvider._sendAsync( - { - method: "wallet_watchAsset", - params: { - type: tokenType, - options: options - }, - id: id + currentProvider.sendAsync( + { + method: method, + params: { + type: tokenType, + options: options }, - (err, added) => { - if (added) { - console.log("ADDED", added); - } else { - console.log("ERR NOT ADDED"); - } + id: id + }, + (err, added) => { + if (added) { + console.log("TOKEN ADDED"); + } else { + console.error(err); } - ); - } + } + ); }; From 1a3e906fc73e8e24d1fc70cec1596ad40f8c4cd9 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Wed, 13 Mar 2019 14:06:51 +0100 Subject: [PATCH 03/31] add token button in user balances --- public/augmint-token-image.png | Bin 2632 -> 39644 bytes src/containers/account/index.js | 24 +++++++++++++++++++++++- src/modules/watchAsset.js | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/public/augmint-token-image.png b/public/augmint-token-image.png index 4a7f1711b93402fb983c21c40badafb05959ecf1..7195bfa285e10b18a9d8545bb52d384eb3ae3546 100644 GIT binary patch literal 39644 zcma&OcQl;e7e1;bh+u?}L>Y-rL=Ys(3_?Wjy+xNWK@fFxL6lLWMK95Ni5`jGMK4jJ zmr-Yw8N+?$^ZosC@4D-*`v+#dbLNzN_IdWRpM6G{nu;9xtp~U8@bJjxU(0CV;SrEr z|B&1So{(M8S^$6Woi*g7@ydo6w(#&I@#JNswA}G`TS$`_x?S1t>Fc_!*v~UZ?R9mM z?Xvr=lOM*umXELfqI-uelGjkMs@B5m<15Hyx97)?&lfiihdkZ92L=q%RUzHo(_hvq zFZ3U|MrX?eu)Yq!Yb1>YNijrXTd`$*k%<%KR5&*sSt~1RZJi0SOpI(t)73y<#OHws zmv|Z}Ns#SxA{`WZu;l}9lcfN(^4VJcm+yr??{vFP&c#voU_<@0A!tKN9fCVfg*#$0J9(yoEOdt$t}n4ecS&i9S4(%atcTwjNCt2bx|QlI;JzFG48<^LF;jDR=FZ|v{6A|^mG8>Huag=4f) ziEKZZ`X6R~J5P&pHEjChou!&_;gzs*@)m?~Ic3N3 zi2nKDClgx{Hx*dmR$GX_CQ67|657nwBxDKs2zGkLa)-`b1_UC?r;5h^`HV(`im2%2 zn^DYVa86uY%Z(`{?{fu8qUQD=jGoqSq+Drbc|ZhFjoE99HOd~melhgMi(SzD zaH*`{e>b#(nVDojQt~E=;8OG_W;G`NNcs$0F^JDmS#zJm6h|&`4T@I6aKzX|@jF^l za+sT8)aP^)e@^jj!a}8}+t>~`3` zM(YPV&Uge`uCVaTx zd@;D*TQs3h+}U*aC*v^m>cSFb(vi&^tpx0C^Z@dax@@RqcUP-W9QF1u6)8#*hEslz zMrLV8!`^rw18Ke!6r)I9`jF*>APe!$s9Ft7tliE-z;Kgu>&h92nyL~B7)oEv#Od9m zA-V8sqCH0Cj2c!wXCl;Kl!IqA+1pdFFWNc7U47pzIEDBj#SQ;^fFDRlEPdXZeJDvr zJ-D@i`H{=*-KV}6=PCO$_1%WCc =Z&7YvJb7X>V<9hAyrs5{qKbnr=jaTrZ-6j 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

Z97%p3`aO+Q|1Q!4yuImd0Nm?d z5rGo$W<5W#tJfS{hg=@yl|T=5AqPj38efJuary9pncyg~EK)qvG|iWyMZ_8;xm%Pn zB1hw+1t~FH4OZDWzkQk|g~oc{VcfveI2bSaHCCRVU3DEVYX8F3zDcIB%5$Jz&2L8s zATRT=VetvPovN!6GkSYCZ#~Aq$SLJJ7qa&ZwbllCQEVKk1v+~p8>?8JwqRE?&U@{z zKd|dd_FN6FL;wJpssbN-No6b&$^)2Fk;$DVyRQp7)-@Z9ucTW1F&eecf{@wo!^90q z6ijYojRK;4?2QdJ5rWTaBnoM8V}Og_#$wH#|D&$M?VY9T7%c|E)I;tC%h71LI@CT> zBTw+Y^?5St6Dr?VwyhxkEFwHC-vPSIh#Z2~n?X8cr_~vZj6pn;2G!+XN*s0qLw5L$ z@iy;+9^(2{7;Wx-_dFkMJDD$XoGeUtj5y(L&p5uPNZp`pNQX=5FmlXAT@e8+jgPO; zOnoGzF}(Hae#~(f!`9A<$;>Hcd3Y5uu>zT)A zSdTrAGg4Iz0B-|zd;kOl1e8-BN$x6Vq!1=>=x!sbVq)6A`yrBr zrmU)}R>0@!7#&&Z)5%6x$nFSldBpT}F={7V=fUg%iwvPW4?1_p*}x|}f_x}%FZiZ# zSNF9I1jLgR>akGFZf&z`H+P9unO@Znx%sw-qFQa{V1skVW#$Z2N#ojN3AXfN@#*~l z`D%lF4DB|_o%!)`K~Yp4cOcOhE4l7R#s{JYX&`!B46Fj3;^z_KZZN%XubO(+Z?_Z` z2jje*#%mVg9JOhuGM+gu=x@j)M^o%hdci4ud7a3=;o zo2mcO9sh#6-FKeO3VsAF1V}!PI~e1g@aRNPk9#>_snHM@o z8l(YuO)20M=!l#<1Y0xe@c%Z{GXRVKS)$5rKWH`K!1b`s zzVh`Z5!9iz;J^q6q%Z}M$`E48s5EibMGMyEMi^2QD={o-5pwIYy(v=I7jI*!(`D>t3-e3xZCpNG&LulKT=`{kdA}48fPAXE4SMKmwd%e#B^JNOgiqH9>$MrL<{NB@yc@3~I2ILKZGv^iU zhzwywlN&F+WJjytUWx5)rjMUAvd;TfrInSj4 zfuR4wn)6P;Qq5nAWkcNsXwmA`|Ip?}&b~DMq0L3?%g)}VP z0m;4hq2N4+Zw+4oQo`l812TfCXA)}x0Q#}%e|-Q!->J%ilD`M~@>KFV+*7W^?=8i2 zO1f0y7TJK-P2AA%fdSlso{z2@=lC1JflogR5oTc1KX6dg)(O@a<{s4qO0npWtBMT^+P4FQf@=(OKSL}UbkD#M~` zuncqOSd$8cE9>SY`+{1mr2d=hcQ>hPIsXJL^O;5;bkTn@o0$SEHvS$ z0gm-d_N%{SJMMrVTFGKJ?Uvi{gG-Gi32?yAWmX+9d3nEie=M>f2pNPTiwKM02DYz( zHEX1U&EF&Y|Fa_>!8|-)k7>jT=Ph`Gmw*JThkhZCZCUQ72+~^!8s^%8;a5>^*eD9D zKK%~j0ewkeA_8RMf%2*qm4G~{gz{5a@X|YUO~Es*gCOB>6_mt0e8odDdXkuFiVNsDyJGV-OBARy=Nwz<9$#iF=pnO zdK(~wY?g+v7)yt87u^R(n_ko!DUSb0x#VKc)+~lWf`@{t%|@odX{rUk&JIW0dvyS^ znnsEQx6AQ7np%Le92lU_eHXbDkgX$+%2iN^hD+D( zNkvZ?SoH9$=CSrda#oKLEqWZ&SOMfEV6pkEa*(a{)cih3w{aC1L7?>$8U$AkAzHmo zE;F#OwjL5y71)|=a3#R+7RO`a(%=lnNIQ=b_Vis43b+By0P=7xe+==Wf$|SVqh6*i zzQ_wyq7FV%bTQeb3jlXsj*d-|z!um_`-NlF(Dr(Ftj( z*Hyi_EH$aP^eoNM4%p~|qK%ta`Sp;t z!h$DYoM|P@1UI(A0+3i9TkE4F3`*B-sqat^=pcL&AZE=Q!Axo1d)N}Usmzwu`Hm0= zIe4XP2X;@sl~ZGX%1dx;g2?mD($f-3}?h+@$=j`RtBH~mM z6;Jyd0GeFVV|0Yof&-%9TcU*o?`LHbv~KtTTNF!jNAUO5W-B&%C}+KfViCxr!{Sm^ zWZ(1fe7~zfe1J(P;QbOnZbK*zrOvA^Z2#=D0cq~xxy6zv)J+KF?H(8mgx{uvq&(4IY5OX$T5$QsKPk^BQ z9wY70B8~_fbi&AfR;oKRGsv}rI3 zRcq9v_S}7#bo6XNG4>Wss8ahn-i-^>sU;Cjz6X4;j05j07Lx8}{wgp&k@iM)e!7Gw zwd)P5YB8)iVIPuPP1x@%6n7J~%DyZ;smOX(WK?Tlc4Vs6Zj+`N!K&@U*7Z{waavL=F_g?|8tNyJN`b@<<_h8Cg)SI{3Kr@fk7o zdwd7Yj$c1Q06O=#?Vp$|rc^` zC5F~T)SLaUo-^e&u^aI^9J~k?>y$qL;^B?uOz)k;WlzNpnhJ|=4UeZEZRtF3j`r#b z55}I(@Gd6KeqA24A4Po%GeBKKFI@Y>_+txwjbz`+A=Nb zrp~{>3r=yLPgV9YWwo`AFtY>eN!SfCNFZY_H+C`v`z8g{MviT-S`RYA1+6_z4$C)x zC%(2oDh+5ySVioV3wv*cetAKfT_J=e!N$V#sEHT%$B5|g-A3Z>=-yDR+nRc~!SU)j zy|>IuFCX!m|nMYA4XgjlUo0Kb2Ah9)5=2KgS7kHFu7_-bQqut49^TtdmX?f@;rA`--ZDRBjp=KVFT- z20@+avW*{Svs@PWVH82W)i^C4IX|XxX7T(=zZ!#qbV_51%h3Fqu8{=9?aQdgon4Ul z&jRDZ67l@3z0!0M`_U@p-#EiNSI$NU(_s?pPf=PHoOyEeeHy_G{pS;5b3^<`>k7%!$#CWG_d9U5H~k#g zwyzJ@eyRi9I>+HhJD|Qf4kvd%4Ng%>^oJ!-OC#$kRP@~rOjuM1#HX>h>klwgIH+0x z41 z7R`7#vu^;hmtM7e4j1>?=;92ga~-st6XIVfxf0V!;!t|L_KVjn&Ke+aPxfX6##Q?A zR!?TA3e9S1*zsU`Sj4d{Pz?d#ex?mw)s=&Q5&?i>i~=gF0KGJn6j*mn$$1Ji^#KAI z01FQ&4*zB0S)4oPOYO+L;!92v`2#dfFqtF=)NV`aE{o>|)1O#KyY>0CT(~>s`ouk# ztukhD#`w}2yW)KQ7jZkD;Jsq=TAJY`BgziuU9)L>m!ue;*zKc zAcs>-u5(8XRb0`HV3~fTXm*TOEA;4lqL|5LuA4uHTkN_2^CP*sjb2+hItKt*-|sDm zWBS_uwi5-dw-&w*{Dbnzp4 z#F}J_XtlmZQZgk6JHG{D>;7JH=Wqa4U4*D{1r1+Q4X|>knSQrU zJmSrN1}HP-M-2{IYsoNw$K4>lp4-n1(6^=21LojON@Rt%H=qkEz(*0OmO!H6VI6%} z;ALKrY~;^H51Gs!R?{3qG%9CAz}>*&p|%8iHQDx?i6D3aDdxqm_qj0(Q%I+FrG_O& z%F$f5IIKtj;P~f{>kP$#Po-%3vEQ@e0&PTf93KlfU`XO%UpyBX=?nyLs^u#K`smXtaDGG^Fd`H{5tA4*-U7KFCEAg?{si)E@E!ptS6zH%YZl zB6*Lqg9-DFQjG@hv_i#iyKW1)U44?E7&(SEt5iruCo1CL-wjQ|p5|Bl>38>uR^n^% zJn{aQAHgPoV9k0%lHwKbNnnQChl!(f>zBYX+`XRHZVaJTGq7akm`}G&olFRoGyLp? zIt)VWYl-O>&iC%UXl$MCL@>#Gxkm^T8fz&VExunLV6C8EtlfzU1Ji{fIv? zrWATTdphW+rbXl-!;AZ-3o>JIq$UH%DEnKtnr*O$@d;&MgC69#NiNFexUEWP#%~F@ zFO}nKCS20-o7Mc1$P2rHpoc-7E^I?s9vlH2dqGH^eGIe2G#6x$6M)JUmlIf$aM58k*TW}q5@%jbW5(?Jq;yzGsfV0QoT*J3!QG#5aNls1zg=an99)efBT0Jm zNRk(aTs&Yw=k!MhGgtItlj2HS`rf1t>$S<5w{Rj<;5_HasJhVs%pDJNzpV0}8nJ1) zs$^Bb~`$(DmYjx{!Zs%uaB!-_8XJFV7Gcl(44^OAO>ONK~% z+--c}4$Rc@4je4H;6|eu$lcOL)z>h{n42Jcn`z%%(9N{7^PTdNcyJ>(O=-XVFI{X3 zub)#SJRmx&n|ExExOrP~>F^kigvEIcJsl!A>I`1ELSE=VbRgGCxe$j&*Inqzr4h6t z|7$TxJ|w?7+OyxR?4vy**-%Y1-A?dv(@y!A9i?u>CuWzvo{Hs3m&_%&gw1S66f)24 z^?0H3|FY2{7mvlPL6msu7b&;2uuZ;qRs+Y+x?u>ibJ$ zod~tq%R7duYc$TS8iZKCpjIA^N7YMjDB!oSa5&tr0^U9JwOhyATa}a;?3I>uhGM)* zBaKohBQcKGOL$oYFQfVm-&TVgU0;KyY_ffaTq8% zwZ84z*>(Ut6*rOx1S>6Vn@*XQZ`DOK9I>`|VO&KN3)O zl+0*uK3jioHKfyYpoH}76dm8;OT1%9Etx8US5 z(~X%+@XF zv6h_a#1|IJ@4Ta{`{Ksk@8v^E9~gH>^kysDR*V2I zPM|In63(aruWSWfZ<0ml%6CgC+53;1-7~cPk&umkkHMtt5rkG0WsRWd^z!wp2~cf( zkZi|hN$?`5_^lN&=2_8=xk>j$Dg&1ba}C1jtgF6?sBD#jv+6CF*?e;Fto2n9N-)MW zUZ7}g{;N+s)P~8W;H+~WmXy>^L6Slqdv{`h<`Z#T_u#5Rva0iqMd@d5FS+sd1? z_h_hN334=VFvMg|=2KVs!s0y2F5jqew&Tlo=2qrXrPDcQ-0McC{+w{6Egpk}jvyee z;Or|P(bVUgz(mgBuDjan?d2P#fVIvjqGV(XEqZ=QI&M@urUmsahcr+>0Dqn92rY~F z8bQ%NH4Qmx-e-7XE%s%LeV64t4^^{Y*l4(0xxemOwBY)1TYKOPNxZ%#9n8?w-cl47 zr0tOFH1J89y^WO@>taSq@Ye?7eFya(FLrWF%ZAS~o`dQK)^fg2Tvw;E&&=CkEL@lD zHH|#NRga^1g)1FH{AQ@AwUremo`Ekrq|exx3Wf7c^O0QB3}zxZV~p_}fSQedH!+sc zOKZbz=R3a#MixHCu~`?M4++lgt>8dvZ%Nqv|8nk^h_OsdG&2^*KH|oXjExSVcA*iK zvS+4y>ma;#qX4I2_|Q+<<*H&*-d6af*=%~>e3b*d{8wic4B}bkQw7zBK>#t-!s+tM za>O*M@URqNF`JHn+0Bnxq(#^nPqn=Oi4vvhyI#)8n{`gS9J-^IO#3$TvR5`etA0|4 zQ3b<$lPJ;C=5-zS@F&^B2g%>|$_bqA$yiL@zKx35Pq0g`b{(v@J71rF*HVt_F7%}~ zH^(*1XjYMleeQKe4s^Fko5@p#xF*7d@f=HtZ z%hTkG`r|rE5?tU4R%}J5>iYxNwcI~WVKY1R@6Jyysgw45{pd@00-cjV7Yr_!OZAZrW;^nvo(_8!CmYGrP^jf&Z zU1?a#;Gy_aLx){DSw`9uGTmQPENe?nlt#|tC35W!{51B@I0fdqo6>*ozR`8|77>8g z`D|S0U+~ea1@8O6uf8iEy{;Z-F`5!ouHIL*ha={%vN=uMzdZ58YI5?q?5JXHp0!qT zxQyX7;cM={G<&L3lP#T*L@v5p(eQ1gE{n_6H%auKwc*w@JLGQRG{HK(K;KHvc_Cy! z?&Xl`%qbBwyVYS-gLFrq+KDbay2Ost-YYmJzT!;2S>}Ixj9z0Z64G^iZ-ebDe+C5; zHO-22b)VcSIy%{uzxA2$5hkX$P?YQ2IaV_{HNu?d978(7grBd;d?uN0RnjplYon6a z5i|sBOq4SuGaFeFdXxNBIe~-@bvceV{4#~XY2>{rNm5qH7{=m}3VvNVX%u9NPvZ4T z*1yZxaGz+KW^P#idQH!zkX^}-H0Ig zZPWwy6bfUEBvse7!_p&H4?03>bqbuCH>2L%Ss+gE6?M^r`CR$!v*Rpze3-1hi2MQ) z_g;uw&iHw`Qj81$NuZ#|nw|@agbboOwk~fz50*qTDyR&_-ty=Gp zPE^_Dvh`EXQ`iFZIx4tmUa_Ek#Gd=@Q*U3_M_K$_eI0|MncE+qv`J8E+E#E>)hPoJ zC%ekT@Ji!VKBU;D^AWV%y+>r7RzT08%4l19i>wexiPGRxrSkI(U^Zc#QowJcM;7h3 zA+r`mPKKf+n<;&oW9U;J<;d5}8lA5U0gEvh50^nPo#}Q9e+(OIS52@o+$tIoK=)=y zlR0r$$pthdfs^YJB2}jhUN{msa;V3>j#-ULaYYtEt%a&1AEugJP)c6BoNO$DEf=_ee@m1 z?R;z-!z>V)Tjk-T59Y_FA=5PaG^5RVsKRBL_G+XH)uqD)q4mhA?5O^n`ms7vfI5OE zJ``7I7x_KV0v`e0+1Hx4PMv!8X~@pI{I%7fu$VAlnkZW# z=m5{|cY;0-j*aV4*%cd$RUq<%^g|rKx_%{KRXmMm^9i0i)dx)D2(RnAvRph>WcFCQ ztk()g*Q!QG-LXj;T>4X*d{uSGNa;$%Y1v5KNO|+=#LK#3T~GS}QY*D1J-SO~yU`Gf z%SqLPu_mH^MY~KWBaLB>9gz8t3+N?yu-RQ1aGDju$@JDmjD83dc?sXGj?otTrG8*O z%OT)XoWL{I4y04H;iRQ1Y{ubjh^z+@PO%NT)ggT_cy=gc-wc>I%QCjZJqgQiMMdTe zlup4fu$+sF(wsE$MM$3@*>EXcPzyV4*)r=zSt|B+H-+gL?nP1=v_x~OoZPnqA zAu;LtT$01g4o$$UHUhGgqQQO9;En5U;-{41R+Cfv3pEJVi%Ka$kn<%c=W8jT_%ul58dTJrMnb@yidXA+ZMwWd`%?i&R zYqM?ZalWfZP_CkpeY3`$-}6Pdf6ACoKSI6%)Ie`cm$i`>KrUy`6)L zr$SlZ_gp+I@^qVd590b@gQdjSgfOwExnC)kPg?|%eYf2PY_u)Vmg1rC;G+G$J0MnNEu-t$=bgj2*dURD3JCo?c+sZLy~+fR`}u)Xfd7o|qZ znUx>tMVN%P;vEiB!>r0t0pwPe_-xe*@mgkY1p)lnbb8%`b+~CLonshbY4}>6lD#r* zW6G#Udh57?y5-uMDY`U8PE+h?QD3``P=m z4IV^W-Q~nFuy0pUQjy#1EUK44MkJ?X$6QyHz!Oy`UZf=PT1U;AW(*N@S))uc*seOE z0ratVlO)Mo%w1;dr^tGBhbK9;FSyBzt6D@=>NCxfAt{c2X^&|+`i@B8Xi59Wz5DHxi z8hKdd@VU+1x4XaFS1dY9HM#RP%;jxWC5?@PRjD|q$xwXY$F zfratqB3andq=2ngw{1f{PKIYoc!hbrc35|=6-m)=+~}q)JkdF z@5dy7rRN(@BZl;i%2wi4WY3SBsEV_Z5JtrG)x?BAdS%2{f)Hlm(vpqW<9W)q4;50> zGEb-C&mUA-QWS+WqLbF?MBBF8N<|@tnLMRd43owkdFoG!hpWO4M)##jJptFD;oxLO z@p}RJFfLeyzWXZLH1nlFt{uf{!E!LivB(FYCa~5cfKLA>_#YFe$ZA|rOlGLwdpnnV zf|%KhecWwe2M76iI<Bck%HV1YR~PyL1o>@DrXC=Ra07zo zm_QgLn4QPobEy-ER=^tAY9vuN{aq*hJ%w*cIDzy(Ph_-8FJp@F(l)a z64vSB7&+2ZR6)a>4mhZyivA|bf+ROvV&?h0hNX^SVQcZPX&y-62`MHsubr5?&D}#M@Eb6C~U!U{oW1P=; zcBE!TRmP1ur*PI5(#1v4IBa8R+g?5C_70Jq=D}m%P;-n95nf9jAvTaG;&*=TGe+h`82qcxe5HxD8p>UD1NkX4s90VFI}xq+tQL_#+}(b zD2oc(ynC*ahUM!bg#nTT{%9RQ8K%oIj{W)a?5Mk%v*TW>-PykA#?jDXxa!s`v?ydk) z!K}RHwuId4X4N|)zx%JYLd)fsA5cQQYwWdSg8F*R>5_^|^!MiP z-rIwoID{*QUw(Vm*PK0RU?8;+I_Ek%edSNx<95tGX>#ND?PGvE-ebV9&kPb1c3dv> z?>zj`@Of15=gm3r2G7QyOow*hHVBn^l8#PvR>a0KCfw9WI488n$tV!=byx%=!p%GQl?9pjc+>s zd!;bY#@2Vz$IJTEUHbEmt~dNJ*{P4bVZJIW_#_9I|GXGJU@Z~e?{3wh%%;u3jO!^Y z7cs#3ayCty`5w+c4|O2#+Yj;j)oW^BTi;F_X-=>`sr}HP?$elD)*YgM+SCR5I?V~P z5u0A~mt1zQJ^=agbCq0(9!)Gs=mvrQxz-Nt!f{{P^1*b}<8 z(8DIjL6FmEvGKXx8-Nh~bLTU}Z|$d$o;uo95hQCmA-CU!NZs^4Mv9ljld!KAP>(B- zGyG$ED`^;w-231c9da~1p6MdZtuwD9vm9zsc0Q8ewF>nyy1z4G9C+0)L|s=!x;10i zM%ZsE_{`Et{K%|GZT60`%9+MNki_TTJ_*l?>_E3-&;OalIr9Zq=<70u@_RC{qv-e z?3gIJ9PjH-`BeHwKdaJ?r8zIyZ+_=HN3oS4*(FXMc;Fwh|7ZB@=oikLb;;*Zja8Ki z@17a*O1)AAuH1JS^2<=R8RcfyF+)iGkEzcwEO_peJdVk1zBZR4Wii~p<4+xAhE3{q zr=Q;P(ZHV<$HOSuPc`yOJV{{aYQgaEj=!v+PkY_xq|Hs0BeB-W|BQB)QVW6&c~T-; zWvV&e7?TSxrrm2fltc>es`fjTZ`$L2y!p>7e%jJ^P@6-+j5E_#>~T}-L+I+y@8Y6L z0qe?99swLdcmHW-1$>99-on~(o5Jcxk7;OeLwkl)LPD6A=$^kmg#532v<&n;oN+}v zS{p{$IcWU>Nx%p14*$UGXmfYY|9Gp&SPYov=}h!UGmE#O51>Q&Ma*k8TZ-#4i`4CQ z2oF~m@$W&Q4FaXQcGX@Luo3r*!P>SpRPy0~M`fp$_Ygb|(qs&J_2;#S%lY;*HgX9s z_#vi(?jy8CJ>T{pX1A}$Z$8HI9_eoV{>KI-88FxD!C#d_y@iLqDc$i{A_)k6K?t&c z<C1=eXB0@?*@HPJt7S2+L-+=k9ub&~i79^E7gOCgMN-=^;^u(@mJD zhm~WCn8(&Fe_M>(oV8np`ShKFL*q1@@&CGnZ=el$DCgZ&0f)=ar0G)*@H%KCGc&GO z9yVKv!Hc4wwm;yB^-yBD>)-K;6|=gZGhs~4&c|GT2v_D9p09t$Bg3slsmbTI;WOdl z-p>JlEF1$yaY{K@5Q9C3<>BJrk_HwiUBz2Jqj^+mK`pZAZTiO@TguZeIAO!+AL>Ee z&HBCiO6P=tyMwXebBN0#ck?a&`oB3kNe9J?YGAje1gRR)<~emp4C>(V+#AJ5$3bR@ zp%7E-pQ&{O!d!>ic{pzKiVu!|R6RaozuC7|_rL-gnhtzeGeHXHx98fR!t%Pi;3Tzs zRP#>F^H~3m$;)5H)%M@#8iyl1r1pM&^N9U3p`BSVJ;uLBGhPZdHCPP~av)5$?M?h& zMW)qmZSmfH5$+v9t?yNz-}?AZq!uK4J2!m0_x9Z7R2B35M#l~#f|v=HZbh|0e)FA2 z)X*y3C=1q~J0QYx)?d{1xHp7sJbjdvNB0Bt`R?c8_~zxA&B=V41-lRk#%D6LvE5Sj zosXWF7u@R)54~PyyRoatv}x);fC0aV+kGh@Dvo@HdY8L+(>(7_$1G%+D8sJ zs_CnU`djfH(?jhbIxJ*M8H5d6=d*&ptI>PbuYacPElJ-wr*G3YR$WyPQx%OEn=Vge zy!yDYE@y6P)%kgkTO0q|)KSeBh~N}l!XK$w45U7qYn5-%7&+a5UhbbC>5gRG{)sja z4A6meOKm{96BsOB3UNvw>apRd@gG>}+PnF}5h@sSw#a1o>dyp^q`?Y0BMa}AI>h$J zdwN*7(U~UT@Z>DpID>rSJDEM#jX&eWfGJ{rSeg>Cn5LX*X}3)B%>Q1&tbN|i>mYB? z!8T~;?LU@8f$6c<;@a%XhO_Ty>Q4yM?aLH%ZU-Y9k~;SgAKqgu{=OM^u*zLsEG z#t&xqXK+;})U(*w_iQ-pln_J7e7oOD2l`_-fHB-zGv)Tyr^9Q|gmOs<#VLFtx?<$I zs(p^SwGu&e!KJZr|@7rf5xF!k?Z(Vw1EyW76<9$V(a|L7=W$$ z#NJLLiJP5o1FS%p%7l+F+Kas1hjTK=i^UG1&h?8n@1Q0GzkMiS3KLVzouvz?|T?7+JF7r%n=^YSJ%QJ0o=zDZwP|h#|=@*JGynAV~y4b1(|D5lq;xOK`_mDfq&ei(zPd*-tLBo4C5$sC&eyO{Vu$qkLnLe27vL=S& zWz!mgzx7)+DBH-Nq*ZACa&Y8y%ttQfJqF*D5(e@6;{$Ico7KgrY0I*``Av$ux92td z9-!aG1_bMusC0}!few>w^DLZ2WYkBQP(j0YZis?Lg>Jz>b-B~2D<7k zuy?&1v{)^$1Dt_&JPZrRKqUUP9FsZU`|aNQa0QHNve#I>Q>m_z8a~$|bybJXV|H{B z=uve}1wNC0ni$kA)hV|W3j&PxhQj*oaKr?kutC#aTGRT~*TYF#Z1ezheZZhuK7HBQ z*T zRw69}Xk4}0?|}_x@vom(?2Vj@2!t)E9oj`pZhW9q|>B}-~Pc6HCul zhxYyQc*BJ;Re(ZM9}6+GP%Vr(zH=W9S$XpXnliqVF)FBexhLhI(8&0TPgeMU8O~YY z3E`q641UtQ){JZgnXN2wJJ-?SxXx8hO1c_uaR-rjlw#?&K^(`(Iev*B z-tm#=J_WdU=%!m&*KZG9XLmBF8TyQDZcMm#6woLD$#zzh?o{r^Bg#sRqf{H}_jcWvFdnUFpM&|8+9|{q?4D-XDWDpoV|gHobI>ibSk0>`-$@9Mx2tVD- zsN`t)1JtnnzrSOc=*fSF88z1sNqc_}hTKyEHKg86bM>@R9^UP;I{hYS8YSisghJ1= z(f^kuO=(9RmONy2z`Zo4e0N;fL__LCe=h2bANKH9@9WB=Zy~mNdp~4>H+=7cHnl7? zIX#F(5dSPGw!DC1nTP>z>6F7>=Lg3VXKR(eOqGoen4BAfL;}v@&78&4*ExB&cCH^R za1;KwPV89x(MY0dsUu_kl)!nW^DnlmB4EitP@?rn$S)SE(eHJ;;r>8-^w3*-;J+P+ z@jbCb-vVxp8bw9{nF^2@i)PcIf`mAq+c^h%a}`L>`$T?z)-7(q%goYov+%CVi{uY!<+DV5+y{^jpm_4PDKaYnL~if+qIN{mr0rf&M^?SLJIntwOP`0YaD zZL!`&+zv&cPYi}S4Pm$OgxHixUtdny*Z$a&gBe=^7K7cYZrU{Ao$Yv9Nz9$#XcWZ7 z`ShTGErL)e`;B(#5_TRXdQs6)v_!#*wU`GpzdKgdk=j(r=Vi zXClDMi*@82=tCm{hutpJq#@hF`d`DdZl19{Fx6vKtR$=uz3x0Ua6`u!NG*XAf9mK0 zQJ!+p{M)qLklNy-e=lzX2$)3R{Tkb}A!~zT$JL1MPnjOAR-()ynYO3}S+6CaXnBfl za|XSiNffBtm2FM7Z07tov5M;wgPoRL5Q`JCO<@xeAd$i-{?kfXY0==q_hAdl@PH{f z3^sMo^=*ghorJl@*mU};?5fDW-G{P)jRZ`@jVBd}BfK;+T}lI%75rf@Dmfl?kqr4V zeSKw2|A1#otPGAl*-)L;c#{U~dBCViah9`9>p$fKfeW`Y;H2<+OQ+k%>)ipS&7WT? zU2Ke`-;q||hB-eQHU8EcZk~-)g;F{H5m0AB&9o2oB2^`}GK6hc6J8 z7c<|irr{cr<+2uAggpH97MV?wL(CDe*Z>WtG;2pCOk!11n)xziT>Ry+_K^5)y_FvY z3KozR<6^f<^@NN3S4yfaIlVcqa=j$ZDSr^gh_ zHYb#`fY_LrS0J2Qlx4r07%oI%Psnx970;_U(u_4SW*EYDO}xsJB^(CIEggGQ;(sl< zAV`C{)pghoeAQHcmZXXP;HmvPuRYK*laHa2!4sLS6{7i(7T?@+Yvtrg(;pxh6I`y4 zc3PyBUC;9iFu|OMA%3T)-AzNWx^g=-Yk(Ziag=%ki%2(Yo2L(V7we1pA zYYTYvFumJ8dM7z$x%E0kip%sj$XLXlj2_VlFM>%kEgDwYwtq!9%-?3}ht;qS%=0AY}zsrkj!O1Bj#d z&#X*~HqIt=r1F$pUrV*5%Ph||JNH9KAVGFA$Z_H_BI$Up^Dg=iO#L$xCy2W?6KqnX zW&O=7c+KM~t>%*o;)zOY$!F1I#C7;b3I+u=S}tkg3h`oN&fBFYH}+=NW00A^P$$z* zaCd`bf4`%!YQInVwdAm8GoCu-L$;_;K0_P+a^^Ng&WrX4J6ac^k4IZJls#b1 zJuvoh%?^Db0VPkIjcWgB;tVmfz_`>oy9(Ec)%+zi2IrIL6ph@Mic#G_U2!7Z4h>o? z$O+t|-GB;oXegoYjXzJirv(My*P_;%({&_s<@eR#Kr0gI*u|4PWl)JF8R{nJP%x~- zkZEQO%B-uk#XoD}*oWlDB+w}x>Q?tYu;j12NseQR|AI_4=lHd+7=Mj$T{VbKF&Q@_ zx`&2*(BdgA)V+V^QdDZR+J=t%e&ak2H%XEnoAa4iv^Jn%^uR>UXhilKhv9J|XDkAi zn`Rwu8fppQ{o-a>UGcGg^FziJ{=34XQ7_eoyeVqesR{4GUO6b*_Zx#BiB%#F=Jf0p zc|Mte1K0OOf6h%9kQ6~9K(Igrsl7JlQSzmMf@J69`Nk`;;}%8RhP(zSKXX50o%$~m zvNZ0Vn>;_5k;D*nI&|qr5M@6*!g~M6GC-aH1D>sO{=walP_RU`vTC))vGK}MC@FhH zFqxzl7S?Y7(kGKShvS~o5t22Q{N-AO z4R?}j_)gN$Hka)eT<+rW;0eRjvfj!lrKD*x+QRX%P7w7CI4T30r z{@A)oI|uwT!IfO)B75TWM1LFbu-M4A?VwM^kE|2^9~8}j)v3<2MN3W)Pt#j|3CgF2>oEmKi-Q4wE^(c zEng@;+Bd1o+Wk+TNG=p%M3=rN$F;}31TN8LeSWiB8roX@)JYnDF>+>5(jVQNKt&xk zYMHX$;OZ{KGqC}s%ciNNd3G?1HJtsXdFo@3yO>qb#~<0+=v_C2Z}q6Oo!xB~IZIny zCQ>*@RI8$kz%!K@?j1?Bk(P31kECWr-^W=zbTIFYQ!pTekyaaQ?x7d$id3Yi4b+yc zPj&frl{mIMvMI#5*JfK7s;icwILb0zuQbR}pH=m@hh<(x> z<$|9qO0Fn#GXrV8AmSyL?LuDd8uxdej`Z}`uS@)MO z*T$td6PM(NwQh`U7}ANp%Q1Ey+WEP$@Vv!F!JQtQbam3sC1tq>9LjhqU9F)tGP;Ev qM)=4K9bHjzc-(C)1&|q!VUl$Pa!-)k?Avw);5*`R+@0nYoccd?oW!pH literal 2632 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 @@ -38,6 +46,19 @@ class AccountHome extends React.Component { loans={this.props.loans} locks={this.props.locks} /> +

+ {isMetamask && this.props.userAccount.tokenBalance && ( + + )} +
@@ -75,7 +96,8 @@ class AccountHome extends React.Component { const mapStateToProps = state => ({ userAccount: state.userBalances.account, loans: state.loans, - locks: state.locks + locks: state.locks, + web3: state.web3Connect }); export default connect(mapStateToProps)(AccountHome); diff --git a/src/modules/watchAsset.js b/src/modules/watchAsset.js index 02d41789..6412b6b2 100644 --- a/src/modules/watchAsset.js +++ b/src/modules/watchAsset.js @@ -6,7 +6,7 @@ export const watchAsset = () => { const contracts = store.getState().contracts; const tokenType = "ERC20"; - const image = "https://www.augmint.org/apple-touch-icon.png"; // TODO + const image = "https://www.augmint.org/augmint-token-image.png"; // only works after deploy const id = Math.round(Math.random() * 100000); // TODO const method = "wallet_watchAsset"; From 357338163439dcafc62d76e28dbe47b09bac5f42 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Wed, 13 Mar 2019 14:09:51 +0100 Subject: [PATCH 04/31] refact watchasset --- src/modules/watchAsset.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/modules/watchAsset.js b/src/modules/watchAsset.js index 6412b6b2..0fe6a20d 100644 --- a/src/modules/watchAsset.js +++ b/src/modules/watchAsset.js @@ -17,21 +17,23 @@ export const watchAsset = () => { image: image }; - currentProvider.sendAsync( - { - method: method, - params: { - type: tokenType, - options: options + if (augmint && contracts && currentProvider) { + currentProvider.sendAsync( + { + method: method, + params: { + type: tokenType, + options: options + }, + id: id }, - id: id - }, - (err, added) => { - if (added) { - console.log("TOKEN ADDED"); - } else { - console.error(err); + (err, added) => { + if (added) { + console.log("Token added to your Metamask wallet"); + } else { + console.error(err); + } } - } - ); + ); + } }; From 2ba03f18801d4177edd1a131609fb2ba5c4edea2 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Wed, 13 Mar 2019 15:27:38 +0100 Subject: [PATCH 05/31] watchasset ux changes --- src/components/accountInfo/index.js | 25 ++++++----- .../dashboard/containers/topNav/index.js | 44 ++++++++++--------- .../dashboard/containers/topNav/styles.js | 5 +-- src/containers/account/components/Balance.js | 3 +- src/containers/account/index.js | 30 +++++++------ 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/components/accountInfo/index.js b/src/components/accountInfo/index.js index ac6d6d17..980b957d 100644 --- a/src/components/accountInfo/index.js +++ b/src/components/accountInfo/index.js @@ -6,6 +6,7 @@ import AccountAddress from "components/accountAddress"; import { StyledAccountInfo, StyledAccountDiv, StyledAccInfoLink } from "./styles"; import Icon from "components/augmint-ui/icon"; import { watchAsset } from "modules/watchAsset.js"; +import Button from "components/augmint-ui/button"; export class AccountInfo extends React.Component { render() { @@ -72,18 +73,18 @@ export class AccountInfo extends React.Component { {isMetamask && data.account.tokenBalance && ( - { - e.preventDefault(); - watchAsset(); - }} - className="addAsset" - > - - Add Augmint token to wallet - +
+ +
)} {showMyAccountLink && More details} diff --git a/src/components/dashboard/containers/topNav/index.js b/src/components/dashboard/containers/topNav/index.js index 0bd88a78..5ec7eec1 100644 --- a/src/components/dashboard/containers/topNav/index.js +++ b/src/components/dashboard/containers/topNav/index.js @@ -121,6 +121,10 @@ class TopNav extends React.Component { onClick={e => this.toggleAccInfo(e, true)} className={this.props.showAccInfo ? "accountDetails opened" : "accountDetails"} > + + {shortAddress} + + 0 ? Number(tokenBalance).toFixed(2) : 0} A€ - - - {shortAddress} - + {tokenBalance && isMetamask && ( + + { + e.preventDefault(); + watchAsset(); + }} + className="addAsset" + > + + Add A€ + + + )} { this.toggleNotificationPanel(e); @@ -176,28 +194,12 @@ class TopNav extends React.Component { title="Under the hood" to="/under-the-hood" data-testid="underTheHoodLink" + className="connected-network" > {this.props.web3Connect.network.name} - - {tokenBalance && isMetamask && ( - - { - e.preventDefault(); - watchAsset(); - }} - className="addAsset" - > - - Add asset - - - )} ); diff --git a/src/components/dashboard/containers/topNav/styles.js b/src/components/dashboard/containers/topNav/styles.js index 8302c6c0..25583b42 100644 --- a/src/components/dashboard/containers/topNav/styles.js +++ b/src/components/dashboard/containers/topNav/styles.js @@ -134,7 +134,6 @@ export const StyledTopNavLinkRight = styled(StyledTopNavLink)` display: flex; flex-direction: column; font-size: 11px; - border-right: solid 1px #cccccc; &:not(.accountDetails) { &:not(.notifications) { @@ -151,14 +150,12 @@ export const StyledTopNavLinkRight = styled(StyledTopNavLink)` } &.notifications { - border-left: solid 1px #fff; :hover { border-right: solid 1px #fff; } } - &.addAsset { - border-right: none; + border-left: solid 1px #fff; } `; diff --git a/src/containers/account/components/Balance.js b/src/containers/account/components/Balance.js index 7858c0b0..8010ddf9 100644 --- a/src/containers/account/components/Balance.js +++ b/src/containers/account/components/Balance.js @@ -37,7 +37,7 @@ const sum = arr => arr && arr.reduce((acc, item) => acc + item, 0).toFixed(DECIM export default class Balance extends React.Component { render() { - const { userAccount, loans, locks } = this.props; + const { userAccount, loans, locks, children } = this.props; const activeLoans = loans.loans && loans.loans.filter(loan => loan.isRepayable); const activeLocks = locks.locks && locks.locks.filter(lock => lock.isReleasebale || lock.isActive); const loansAmount = sum(pick(activeLoans, "loanAmount")); @@ -70,6 +70,7 @@ export default class Balance extends React.Component {
{userAccount.ethBalance} ETH
+ {children} ); } diff --git a/src/containers/account/index.js b/src/containers/account/index.js index 71b702a2..e6014cc6 100644 --- a/src/containers/account/index.js +++ b/src/containers/account/index.js @@ -45,20 +45,22 @@ class AccountHome extends React.Component { userAccount={this.props.userAccount} loans={this.props.loans} locks={this.props.locks} - /> -
- {isMetamask && this.props.userAccount.tokenBalance && ( - - )} -
+ > +
+ {isMetamask && this.props.userAccount.tokenBalance && ( + + )} +
+
From 7ff6c724bf4e2c4a8ccd1669ebd3b3c46b25cb3a Mon Sep 17 00:00:00 2001 From: Adam Ridovics Date: Wed, 13 Mar 2019 16:26:44 +0100 Subject: [PATCH 06/31] feat(Disclaimer): add checkboxto modal --- src/components/Disclaimer.js | 56 +++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/src/components/Disclaimer.js b/src/components/Disclaimer.js index b3c46852..3becae15 100644 --- a/src/components/Disclaimer.js +++ b/src/components/Disclaimer.js @@ -3,20 +3,47 @@ import React from "react"; import { Link } from "react-router-dom"; import { default as Modal, ModalActions, ModalContent, ModalHeader } from "./augmint-ui/modal"; import Button from "./augmint-ui/button"; +import styled from "styled-components"; -const dismissedCookie = 'disclaimerDismissed=true'; +// import { reduxForm, SubmissionError, Field } from "redux-form"; +// import { Form, Validations, Normalizations, Parsers } from "components/BaseComponents"; + +const dismissedCookie = "disclaimerDismissed=true"; + +const StyledInput = styled.input``; + +const Styledlabel = styled.label` + display: inline-block; + margin-bottom: 5px; +`; export default class Disclaimer extends React.Component { constructor(props) { super(props); const dismissed = document.cookie - .split(";") - .map(cookie => cookie.trim()) - .includes(dismissedCookie); + .split(";") + .map(cookie => cookie.trim()) + .includes(dismissedCookie); - this.state = { dismissed }; + this.state = { + dismissed, + checkbox: "" + }; + this.validate = this.validate.bind(this); this.close = this.close.bind(this); + this.handleClick = this.handleClick.bind(this); + } + + validate() { + const checkbox = document.getElementById("disclaimer-chcekbox"); + if (checkbox.checked) { + this.setState({ checkbox: "checked" }); + return true; + } else { + this.setState({ checkbox: "unchecked" }); + return false; + } } close() { @@ -24,21 +51,28 @@ export default class Disclaimer extends React.Component { this.setState({ dismissed: true }); } + handleClick() { + if (this.validate() === true) { + this.close(); + } + } + render() { return ( !this.state.dismissed && ( -

- Augmint beta test -

+

Augmint Disclaimer

- Augmint is in beta test. The tokens issued by Augmint contracts are not legal tender. Use them at your own risk. Do not participate unless you have read the disclaimer. + + + I have read and agree to Augmint's Disclaimer. +
-
From cdc494d819eb87aefc11ce584968656d0bcc3a69 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Wed, 13 Mar 2019 18:01:35 +0100 Subject: [PATCH 07/31] new component for watch asset btn --- src/components/accountInfo/index.js | 25 +----- .../dashboard/containers/topNav/index.js | 18 ---- src/components/watchAssetButton.js | 90 +++++++++++++++++++ src/containers/account/index.js | 15 +--- src/modules/watchAsset.js | 46 +++++----- 5 files changed, 114 insertions(+), 80 deletions(-) create mode 100644 src/components/watchAssetButton.js diff --git a/src/components/accountInfo/index.js b/src/components/accountInfo/index.js index 980b957d..77c8936e 100644 --- a/src/components/accountInfo/index.js +++ b/src/components/accountInfo/index.js @@ -5,8 +5,8 @@ import { ConnectionStatus } from "components/MsgPanels"; import AccountAddress from "components/accountAddress"; import { StyledAccountInfo, StyledAccountDiv, StyledAccInfoLink } from "./styles"; import Icon from "components/augmint-ui/icon"; -import { watchAsset } from "modules/watchAsset.js"; import Button from "components/augmint-ui/button"; +import WatchAssetButton from "components/watchAssetButton.js"; export class AccountInfo extends React.Component { render() { @@ -21,14 +21,6 @@ export class AccountInfo extends React.Component { toggleAccInfo } = this.props; - const web3 = data.web3Connect; - let isMetamask = null; - - if (web3 && web3.web3Instance) { - const metamask = web3.web3Instance.currentProvider._metamask; - isMetamask = metamask ? metamask.isEnabled() : null; - } - return ( - {isMetamask && data.account.tokenBalance && ( -
- -
- )} + {showMyAccountLink && More details}
); diff --git a/src/components/dashboard/containers/topNav/index.js b/src/components/dashboard/containers/topNav/index.js index 5ec7eec1..5d72ddf4 100644 --- a/src/components/dashboard/containers/topNav/index.js +++ b/src/components/dashboard/containers/topNav/index.js @@ -2,7 +2,6 @@ import React from "react"; import { connect } from "react-redux"; import store from "modules/store"; import { dismissTx } from "modules/reducers/submittedTransactions"; -import { watchAsset } from "modules/watchAsset.js"; import augmintTokenProvider from "modules/augmintTokenProvider"; import ratesProvider from "modules/ratesProvider"; @@ -155,23 +154,6 @@ class TopNav extends React.Component { /> - {tokenBalance && isMetamask && ( - - { - e.preventDefault(); - watchAsset(); - }} - className="addAsset" - > - - Add A€ - - - )} { + let equal = true; + Object.keys(c).forEach(key => { + if (c[key] !== this.value[key]) { + equal = false; + } + }); + return equal; + }); + + if (!contains || !contains.length) { + this.newCookie = [...this.cookies]; + this.newCookie.push(this.value); + this.isAssetAdded = false; + } + } else { + this.newCookie = [this.value]; + this.isAssetAdded = false; + } + } + + render() { + const { web3, contracts, augmint } = this.props; + + if (web3.isConnected && contracts.isConnected && augmint.isLoaded) { + this.value = { + tokenAddress: contracts.latest.augmintToken.address, + network: web3.network.name, + account: web3.userAccount + }; + + const metamask = web3.web3Instance.currentProvider._metamask; + this.isMetamask = metamask ? metamask.isEnabled() : null; + + this.watchAssetCookie(); + } + + return ( +
+ {this.isMetamask && !this.isAssetAdded && ( + + )} +
+ ); + } +} + +const mapStateToProps = state => ({ + augmint: state.augmintToken, + web3: state.web3Connect, + contracts: state.contracts +}); + +export default connect(mapStateToProps)(WatchAssetButton); diff --git a/src/containers/account/index.js b/src/containers/account/index.js index e6014cc6..e70bfe5d 100644 --- a/src/containers/account/index.js +++ b/src/containers/account/index.js @@ -13,7 +13,7 @@ import { EthereumState } from "containers/app/EthereumState"; import TopNavTitlePortal from "components/portals/TopNavTitlePortal"; import Button from "components/augmint-ui/button"; import NoTokenAlert from "./components/NoTokenAlert"; -import { watchAsset } from "modules/watchAsset.js"; +import WatchAssetButton from "components/watchAssetButton.js"; import Icon from "components/augmint-ui/icon"; class AccountHome extends React.Component { @@ -47,18 +47,7 @@ class AccountHome extends React.Component { locks={this.props.locks} >
- {isMetamask && this.props.userAccount.tokenBalance && ( - - )} +
diff --git a/src/modules/watchAsset.js b/src/modules/watchAsset.js index 0fe6a20d..11e15d0f 100644 --- a/src/modules/watchAsset.js +++ b/src/modules/watchAsset.js @@ -1,39 +1,33 @@ -import store from "modules/store"; - -export const watchAsset = () => { - const augmint = store.getState().augmintToken.info; - const currentProvider = store.getState().web3Connect.web3Instance.currentProvider; - const contracts = store.getState().contracts; +import { setCookie } from "utils/cookie.js"; +export const watchAsset = (address, augmint, provider, cookie) => { const tokenType = "ERC20"; const image = "https://www.augmint.org/augmint-token-image.png"; // only works after deploy const id = Math.round(Math.random() * 100000); // TODO const method = "wallet_watchAsset"; const options = { - address: contracts.latest.augmintToken.address, - symbol: augmint.symbol, - decimals: augmint.decimals, + address: address, + symbol: augmint.info.symbol, + decimals: augmint.info.decimals, image: image }; - if (augmint && contracts && currentProvider) { - currentProvider.sendAsync( - { - method: method, - params: { - type: tokenType, - options: options - }, - id: id + provider.sendAsync( + { + method: method, + params: { + type: tokenType, + options: options }, - (err, added) => { - if (added) { - console.log("Token added to your Metamask wallet"); - } else { - console.error(err); - } + id: id + }, + (err, added) => { + if (added) { + setCookie("watchAsset", cookie); + } else { + console.error(err); } - ); - } + } + ); }; From af01b6f83478f69f27af3f244b76ea57ac38c4c0 Mon Sep 17 00:00:00 2001 From: brigittaforrai Date: Thu, 14 Mar 2019 14:42:36 +0100 Subject: [PATCH 08/31] watchasset button refact --- src/components/watchAssetButton.js | 27 +++++++++++++++++------ src/modules/watchAsset.js | 35 +++++++++++++++++------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/components/watchAssetButton.js b/src/components/watchAssetButton.js index 724058f9..17f6f782 100644 --- a/src/components/watchAssetButton.js +++ b/src/components/watchAssetButton.js @@ -9,19 +9,26 @@ export class WatchAssetButton extends React.Component { super(props); this.addAsset = this.addAsset.bind(this); - this.cookies = getCookie("watchAsset"); + this.cookies = null; this.newCookie = null; this.value = null; + this.state = { + added: false + }; this.isAssetAdded = true; this.isMetamask = false; - this.hasAugmint = false; // todo missing + this.hasAugmint = false; } addAsset() { const address = this.props.contracts.latest.augmintToken.address; const provider = this.props.web3.web3Instance.currentProvider; - watchAsset(address, this.props.augmint, provider, this.newCookie); + watchAsset(address, this.props.augmint, provider, this.newCookie).then(res => { + if (res) { + this.setState({ added: true }); + } + }); } watchAssetCookie() { @@ -45,12 +52,15 @@ export class WatchAssetButton extends React.Component { this.newCookie = [this.value]; this.isAssetAdded = false; } + return this.isAssetAdded; } render() { - const { web3, contracts, augmint } = this.props; + const { web3, contracts, augmint, user } = this.props; + this.cookies = getCookie("watchAsset"); + let showButton = false; - if (web3.isConnected && contracts.isConnected && augmint.isLoaded) { + if (web3.isConnected && contracts.isConnected && augmint.isLoaded && !user.isLoading) { this.value = { tokenAddress: contracts.latest.augmintToken.address, network: web3.network.name, @@ -59,13 +69,15 @@ export class WatchAssetButton extends React.Component { const metamask = web3.web3Instance.currentProvider._metamask; this.isMetamask = metamask ? metamask.isEnabled() : null; + this.hasAugmint = user.account.tokenBalance > 0; this.watchAssetCookie(); + showButton = this.isMetamask && !this.isAssetAdded && this.hasAugmint; } return (
- {this.isMetamask && !this.isAssetAdded && ( + {showButton && !this.state.added && ( )}
From a2fd70269c653d9e4addddb90de9543895cada5f Mon Sep 17 00:00:00 2001 From: Adam Ridovics Date: Thu, 14 Mar 2019 19:04:16 +0100 Subject: [PATCH 14/31] feat(Disclaimer): add disclaimer txt --- src/components/Disclaimer.js | 89 ++++++++++++++++++++--- src/components/augmint-ui/modal/styles.js | 4 +- 2 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/components/Disclaimer.js b/src/components/Disclaimer.js index 3becae15..01387fd5 100644 --- a/src/components/Disclaimer.js +++ b/src/components/Disclaimer.js @@ -4,19 +4,54 @@ import { Link } from "react-router-dom"; import { default as Modal, ModalActions, ModalContent, ModalHeader } from "./augmint-ui/modal"; import Button from "./augmint-ui/button"; import styled from "styled-components"; - -// import { reduxForm, SubmissionError, Field } from "redux-form"; -// import { Form, Validations, Normalizations, Parsers } from "components/BaseComponents"; +import { media } from "styles/media"; const dismissedCookie = "disclaimerDismissed=true"; -const StyledInput = styled.input``; +const StyledDiv = styled.div` + overflow: scroll; + margin-bottom: 10px; + + ${media.mobile` + height: 60%; + `}; + + > p { + font-size: 0.9rem; + line-height: 1.1rem; + } + + p:first-of-type { + margin-top: 0; + } + + p:last-of-type { + margin-bottom: 0; + } +`; + +const StyledSection = styled.div` + display: flex; + padding: 5px 2px; + + &.error { + /* background-color: coral; */ + border-radius: 4px; + border: 2px solid red; + } +`; + +const StyledInput = styled.input` + margin-right: 10px; + margin-top: 4px; +`; const Styledlabel = styled.label` display: inline-block; - margin-bottom: 5px; `; +let _className = ""; + export default class Disclaimer extends React.Component { constructor(props) { super(props); @@ -42,6 +77,7 @@ export default class Disclaimer extends React.Component { return true; } else { this.setState({ checkbox: "unchecked" }); + _className = "error"; return false; } } @@ -61,14 +97,47 @@ export default class Disclaimer extends React.Component { return ( !this.state.dismissed && ( - +

Augmint Disclaimer

- - - I have read and agree to Augmint's Disclaimer. - + +

+ The tokens issued by Augmint contracts are not legal tender. Use them at your own risk. + To be used to replace, substitute or imitate any existing fiat currency might be subject + to regulatory regimes. Augmint tokens are not to be issued to entities residing under + regulatory regimes prohibiting ownership or usage. Use of Augmint contracts is at the + owner's risk. +

+

+ Augmint project or any party who is contributing to the project cannot be held + responsible for any damages, costs, expenses, anticipated savings, losses, errors, + taxes, third party transactions, fees or delays encountered when interacting with + Augmint contracts. Augmint Project is not responsible for any problems that may result + from the use of your internet connection, our website, the Ethereum platform, any + contributors website, or any problems arising from the Ethereum code. Dissatisfaction + with any goods or services purchased from, or sold to, a third party must be resolved + directly with that third party. The Augmint contracts are provided as is and without any + representation of warranty, whether express, implied, or statutory. The limitations of + liability of these contracts are agreed by the parties on the basis that the user is + aware of the volatility of the foreign currency and Cryptocurrency markets. +

+

+ Augmint Project reserves the right to amend, change, add, remove, or alter parts of the + above text. +

+
+ + + + I have read and agree to Augmint's Disclaimer. + +
diff --git a/src/components/augmint-ui/modal/index.jsx b/src/components/augmint-ui/modal/index.jsx index 377f64b5..7ec5ad8a 100644 --- a/src/components/augmint-ui/modal/index.jsx +++ b/src/components/augmint-ui/modal/index.jsx @@ -42,9 +42,11 @@ export default class Modal extends React.Component { render() { const { onCloseRequest, children, showClose } = this.props; + const _className = this.props.className; + return ( - + {children} {showClose && ( diff --git a/src/components/augmint-ui/modal/styles.js b/src/components/augmint-ui/modal/styles.js index 4a85d3cd..0b843bac 100644 --- a/src/components/augmint-ui/modal/styles.js +++ b/src/components/augmint-ui/modal/styles.js @@ -26,6 +26,15 @@ export const StyledModal = styled.div` width: 85%; height: 60%; `}; + + &.disclaimer-modal { + display: flex; + flex-direction: column; + + ${media.tablet` + max-height: 70%; + `}; + } `; export const StyledOverlay = styled.div` @@ -43,6 +52,11 @@ export const StyledModalContent = styled.div` font-size: ${remCalc(14)}; line-height: 1.4; padding: ${remCalc(21)}; + + &.disclaimer-modal { + display: flex; + flex-direction: column; + } `; export const StyledModalActions = styled.div` diff --git a/src/styles/theme.js b/src/styles/theme.js index 0e93d621..a6652942 100644 --- a/src/styles/theme.js +++ b/src/styles/theme.js @@ -14,6 +14,7 @@ const theme = { opacLightWhite: "rgba(255, 255, 255, 0.1)", primary: "#051d2d", primaryLight: "#2e3438", + secondaryLight: "#f9db9c", secondary: "#ffad00", // secondaryDark: "#d99300", secondaryDark: "#e29a00", @@ -21,6 +22,8 @@ const theme = { darkCyan: "#276f86", red: "#eb5757", lightRed: "#fff6f6", + mediumRed: "#ffa9a9", + // ffbbbb darkRed: "#9f3a38", green: "green", lightGreen: "#fcfff5", From be16df6d772621781dc41b1c1a1604069bea3c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Szathm=C3=A1ry?= Date: Wed, 20 Mar 2019 15:31:42 +0100 Subject: [PATCH 19/31] "My Account" should always go to my account :) --- cypress/support/index.js | 2 +- src/components/navigation/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cypress/support/index.js b/cypress/support/index.js index b799dda0..838a1bc2 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -10,7 +10,7 @@ before(function() { cy.issueTo(100000); // to make tests independent. issue to accounts[0] by default (amount with token decimals) cy.visit("/"); - cy.get("[data-testid=useAEurButton]").click(); + cy.get("[data-testid=tryItButton]").click(); cy.get("[data-testid=TryItConnectedPanel]").should("contain", "You are connected"); cy.get("[data-testid=disclaimerCloseButton").click(); }); diff --git a/src/components/navigation/index.js b/src/components/navigation/index.js index e5e792b1..1283de22 100644 --- a/src/components/navigation/index.js +++ b/src/components/navigation/index.js @@ -96,12 +96,12 @@ export default class SiteMenu extends React.Component { -
From 39718427a48f7924160dbf16d0735fa345f18f8e Mon Sep 17 00:00:00 2001 From: Adam Ridovics Date: Wed, 20 Mar 2019 16:35:29 +0100 Subject: [PATCH 21/31] fix(Disclaimer, support): add missing checkbox to the cypress test --- cypress/support/index.js | 1 + src/components/Disclaimer.js | 3 ++- src/components/augmint-ui/modal/styles.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cypress/support/index.js b/cypress/support/index.js index b799dda0..e404bd3a 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -12,6 +12,7 @@ before(function() { cy.visit("/"); cy.get("[data-testid=useAEurButton]").click(); cy.get("[data-testid=TryItConnectedPanel]").should("contain", "You are connected"); + cy.get("[data-testid=disclaimer-chcekbox").click(); cy.get("[data-testid=disclaimerCloseButton").click(); }); diff --git a/src/components/Disclaimer.js b/src/components/Disclaimer.js index 71817128..9557905e 100644 --- a/src/components/Disclaimer.js +++ b/src/components/Disclaimer.js @@ -113,7 +113,7 @@ export default class Disclaimer extends React.Component { {/* */} -

Augmint Disclaimer

+

Augmint Disclaimer

@@ -149,6 +149,7 @@ export default class Disclaimer extends React.Component { type="checkbox" id="disclaimer-chcekbox" name="disclaimer" + data-testid="disclaimer-chcekbox" className={_className} /> diff --git a/src/components/augmint-ui/modal/styles.js b/src/components/augmint-ui/modal/styles.js index 0b843bac..ecfac577 100644 --- a/src/components/augmint-ui/modal/styles.js +++ b/src/components/augmint-ui/modal/styles.js @@ -32,7 +32,7 @@ export const StyledModal = styled.div` flex-direction: column; ${media.tablet` - max-height: 70%; + max-height: 70 %; `}; } `; From d9b560886a2862d36b786fcceb4d7579717e7aa1 Mon Sep 17 00:00:00 2001 From: Adam Ridovics Date: Wed, 20 Mar 2019 16:49:24 +0100 Subject: [PATCH 22/31] fix(Disclaimer): change unchecked error msg --- src/components/Disclaimer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Disclaimer.js b/src/components/Disclaimer.js index 9557905e..51353a75 100644 --- a/src/components/Disclaimer.js +++ b/src/components/Disclaimer.js @@ -156,7 +156,9 @@ export default class Disclaimer extends React.Component { I have read and agree to Augmint's Disclaimer.

-

To continue agree to Augmint's Disclaimer.

+

+ Please indicate that you read and agree to Augmint's Disclaimer. +