From 4caaf4fcbf24dab7c9cd87d6755d78498325f260 Mon Sep 17 00:00:00 2001 From: Anton Cheng Date: Tue, 22 Oct 2024 09:25:23 +0800 Subject: [PATCH 1/4] chore: add coins --- src/imgs/tokens/usd0.png | Bin 0 -> 2625 bytes src/imgs/tokens/wsuperOETHb.png | Bin 0 -> 1697 bytes src/imgs/tokens/wusdm.png | Bin 0 -> 1893 bytes src/utils/tokens.ts | 21 +++++++++++++++++++++ 4 files changed, 21 insertions(+) create mode 100644 src/imgs/tokens/usd0.png create mode 100644 src/imgs/tokens/wsuperOETHb.png create mode 100644 src/imgs/tokens/wusdm.png diff --git a/src/imgs/tokens/usd0.png b/src/imgs/tokens/usd0.png new file mode 100644 index 0000000000000000000000000000000000000000..aaefa81c36f03fd28bf4fab42af3556601d95b18 GIT binary patch literal 2625 zcmV-H3cmG;P)Px;`$nT#SCWXH*fQfVbD$eDAY!8|e-54D zPQX}4Ntnug{VV2vn-kyYK*`SA+#<4#9FzfKayjGV+SDRk+rNn7O&mxK0$?)gfc+RE z`@3HM{mW{++Wm&6L2RaoThMEYeCg+B<2(l@ZkwD(1{;}?K}a(Kf`ddrFnYV;W(sxZ`#e6&lCut6_iFJ<7)3iF z*_BEUjaq>CC|9K3!U**Qq@uopn!acRIaw_9bVD_+*A823%MM4hQ`l)R)a6A%!f5(i z*Gm#YNJCJ<2qawb%)r$anAU;9jT77kI4BG-8!R8Yf|6rWM4eF__yZkS_OB)IpXyW_ zur)OdwrA3Z6bpKf3Y61#0*#Cld>7JDY*CxfQQihV2Tz0TdX45~sl2?T@zOdarJj8D5BVF;e@ zco|!d*XUjv#PI<4c)Fw;F90w5F)V*Y_L2~yC~7r;y^sJgle zM5W5)srjWCKjcRHv_`SLr50;;S4IR!)9+wR&YEmLn#%phn&fE6Ps1;~9I3IX66op1 zuiu|b!En%)DaD=X1`AAbM09@XxaAm>&Iz}T`jSgG-Fk$`l7nFFGNve6%o|zI6TnFq%#4Hmti&2_8L*o-;+YnLf zmu=GWWh-qyv>9!|L)y4VO8_>an5-PB4%kB=LbK}cjL0^NP=5J{a3ozM>u0`Xtw#hG zn6_@RZMnLpEID(Xot8~MxMVauiG$$j=N6Z7>3(+qXFlG5>cd-9QivSJ_JTD(tQ3m@ zfJ6kdchCN+N8~-0-${%_t@FyMm6V#01`1oTkzYPrieOLBZf-HajO>eYEX^DIjbyat z8b)$_nkXeFcqX9XSOYDqU#6W&*R11}V=AFV?FHyicN-qryF`~2TV0g5JnsV#U7?#l zc=IDN?BdJSX%!+o@vjIx!$x{MI5g9&3!0$PjMLoP=AmCQ0jw z7Fw{YO#6e*E|e0Nip3)qOIQ&=z#f0SR5ocwEOhE9XK`*7k(6pAw~xJpZp{0U?e#z?<)CcWQfm7XB z`dXQ^A8S9;2?4_tTrgpwDG8}+rh+g z%VtM=N5O!rkRF{buk71Mq27R|U1_N$s;HU#=2ruWnsCo?Cq_p*>ja#kbNx_vF3N6S zu25D5wO;7h_0Ikp>^%538b99`$%gg`9Zs}n4h6T-)KgZn7mi*B>e}BEl|^EeAck>J zYwb_Bdd>uX&P?c?<8}8sd$uyeqpfO`_e#0*rh6$aI?ld~oSESCA^(XE)VIAa9f1yX z20Lu4iHmk2qrXS;((@4xhw1k(|He`eDoBxusl_Q&R5PRI?90k|WBHIdL-JsHH-g!% z4J!4*bUZwL1yU|ZwIXdPYUjF0f3q9daaF&CEoStn*z%~)RefUTO|!8yBX7la zQnG4cv>p*Au!Fh?W<4ZaUVnf6|MznG--S_@7&awf6cSM`GiMMXDKblN7c;ehsa_y& j1rW8VWnumIdOiOS#oKpJ5EP`H00000NkvXXu0mjfzv~GQ literal 0 HcmV?d00001 diff --git a/src/imgs/tokens/wsuperOETHb.png b/src/imgs/tokens/wsuperOETHb.png new file mode 100644 index 0000000000000000000000000000000000000000..b6b1eb9f8ada27652e4a9ef3eebee38e83e18f6a GIT binary patch literal 1697 zcmYk5dr*_d8i#YFlom_tX+ZGP zYhi9)ek88nUwhPvV_tv8_xlBE4(EY5y~*ty}Hw?RPslIXe@Oq^0G* zO?3^Dc1Am62+6Bgd_JGY=Sii~*;$!Pt=8y}7{x@hf1^+)dwnp+0+R$0M^WhWUzwWt zMtFJq9KpZu_jLbb60C=AR|YMyA>zHgy_pWfFX?MDn)TnyQFeADxnea8btO|gvfR5pu`sUkuFV#FvuJ8yU_a?isfB_^ zG+pAGh3wWf3*wfZxqafm6uMxB>J!Y{7_C2Fo@ypZ-KUDNo*#Ym^EcRVA^AROOav-l!}~W7$e) zi4m4v(c$zeoWQkqr@b6!t!`59FcoaMXqjw`$YMrjWHtUW(mj@mw?FFU>aI~7ux`|z zRWD0^^k^vHhwj<5yH`}TBa9kb^klW1L5`?-;rbcT^vl7B-VAg1_-(ygJN{)kuUh|) zMca%)9b$T6vH#>r$9s6cezUXpe%s4}?MMGO=X1b8{mL(n;`;OC%*{lcb>9-P_fP$P zVRy$H>b%WRWr$_b7q?6vZ%j_09CPN4^t@Xpc^1~A>$SC-*4BRU;U011SW8&wZ0)5j zER#Z7W3kDC@qDI$Cu=-goz!{ertlT(iQWw6=T5+bF~KI)$-@UTE37_iUOv&E f)yn?#gvJbIZTa7NbvN}I^6gMQ-u{>-PXgs1i)P84 literal 0 HcmV?d00001 diff --git a/src/imgs/tokens/wusdm.png b/src/imgs/tokens/wusdm.png new file mode 100644 index 0000000000000000000000000000000000000000..03f1fa98f4a5afbf9d6d3f4ec95e7e1cbe715442 GIT binary patch literal 1893 zcmV-r2b%baP)Px+A4x<(R9Hu)S8Ys_R}_A3eTzT=>40`H5e9LsL?^naGcgg-5s1kMOcy`q5B(*Y z!TxU=BIT!l@t;5T>A;a7n$#eJC7_$e5n&(<>&DTzVr836w z-rl{~{*DCzS4Bw)eH$Jg#?z-y!Fdn>bDceV*7$Gw{}I6Vjg4(Q7(8Y&nNUeQ(t8v)r6KvPqb&|O(s8J4A;4J9IeFJwGYxfTQ`W1&ShW!qY{V`F3J?dwBjMMadosEwAE7G7Lj zjD*Alkys_F!C(-HiHSIU`ZR9dycuPL2RSM~szhsRD^^!mq0{LiGlJ#iCH(kf2g=LK zH8wS0?%lh`EfyS-Wn~4M zHf;(qQ#RH1-~n`uJt!?L{XjUW2(`7f@uI_rML97r;TeUUjK^B2bMKlFp7|_|#iIS2MVO#ubZ*O;|rKP176cnhoDC`Ldi2&o8(9(fR zmoDMjwQER9lKYXzihcou(05E6&D{d3IIQKcJlWR z9#oAB!X+d`w3;v(FJHQhI-3m!L!zcayh~nu@%a~MXlRHTvE}7uLCjEy@#xVb>Me|Q zbaY6PB(3e+w@(d|!C*ij5RCG^s;UY$n=Rxy*OVNE*X#A-%9Sf-Q zqmujaP*}J}=0L>i z@9zie>FMECs|B1Ic8GSAIoE;LH9tQun$_gg z6t-;H5;h$&H8eB?*4x|5^YingS}S>wk&%Jf*;(PeEW_~IZ++Ome}BvfJbd^Ng@uJm z^}!R;F*i2{Ly|!)XSrW6jEoF}_4oJl+}vEXJQU5tBO}-A#4v9S^7&!3miFu=Xw7R^YxJ*hKNdfD*r z!;2|fQj)0lm38983E1!3Lm`ucUteF3n$K#)p3k>}xw)4Z85sd}OsmC$^o$Jk!Xo1r zE?m&0sl5C{eEaQpqF0mmUXK?G?gfu%L^(M*Yi5&Ku%A{+a$XqGWV*RFGPcd-duSa&vR#(Z%tH!zt;dRAM_RBk!iCr(v~PV{r|(dK;=g ztrocz&T)v&xsma~!9keKX7xg%3iJE@uI%h=`7)w4IXTIbl9SX@q3}`(svtCD07F?> zDQ?}mC5)f@zDw{%*?a_IF>-SpgdL!f=$oN zpkT)iRk^^iekO^YQG`>^2L@m=n;}V(8c7;b7-O9#lSxdbX*OY)xn$f@-7^yraHf#`C%G^0N4lMtnY?hGK)Bs*t{|ou(Zox{q(O6& zP6vHloQRUzRCEl%Ku}D>bdCntaMR(?>Etp^NlE$lv0MS+^?Jkrx4P;Rcffi{B~0qR zQeW#{UgF~7gi3?K5M_MB2q+*{R#rN|P!#Y7g!c*))d4fyDWaZ~C;)g6A0IC!;8-gr zs`Up~*Vdd2NR>xzpSTZ{=}7@YpF}vCqA3VE#$1vl{lAyf^*}i166f3r#Ckm!wdi4t f85v`*{d)d42mU%VIXvA_00000NkvXXu0mjf-6oK{ literal 0 HcmV?d00001 diff --git a/src/utils/tokens.ts b/src/utils/tokens.ts index 8cbecad6..333b72f8 100644 --- a/src/utils/tokens.ts +++ b/src/utils/tokens.ts @@ -63,6 +63,12 @@ const supportedTokens = [ isProxy: true, }, }, + { + symbol: 'USD0', + img: require('../imgs/tokens/usd0.png') as string, + decimals: 18, + networks: [{ chain: mainnet, address: '0x73A15FeD60Bf67631dC6cd7Bc5B6e8da8190aCF5' }], + }, { symbol: 'USD0++', img: require('../imgs/tokens/usd0pp.svg') as string, @@ -105,6 +111,15 @@ const supportedTokens = [ isProxy: true, }, }, + { + symbol: 'wUSDM', + img: require('../imgs/tokens/wusdm.png') as string, + decimals: 18, + networks: [ + { chain: mainnet, address: '0x57F5E098CaD7A3D1Eed53991D4d66C45C9AF7812' }, + { chain: base, address: '0x57F5E098CaD7A3D1Eed53991D4d66C45C9AF7812' }, + ], + }, { symbol: 'EURe', img: require('../imgs/tokens/eure.png') as string, @@ -353,6 +368,12 @@ const supportedTokens = [ decimals: 18, networks: [{ chain: mainnet, address: '0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83' }], }, + { + symbol: 'wsuperOETHb', + img: require('../imgs/tokens/wsuperOETHb.png') as string, + decimals: 18, + networks: [{ chain: base, address: '0x7FcD174E80f264448ebeE8c88a7C4476AAF58Ea6' }], + }, ]; const isWhitelisted = (address: string, chainId: number) => { From 43ae673a858751eae58cceba5374e410a80e748a Mon Sep 17 00:00:00 2001 From: Anton Cheng Date: Tue, 22 Oct 2024 09:31:06 +0800 Subject: [PATCH 2/4] feat: remember selected assets --- app/markets/components/markets.tsx | 41 +++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/app/markets/components/markets.tsx b/app/markets/components/markets.tsx index 8a371b2a..9f33f8c7 100644 --- a/app/markets/components/markets.tsx +++ b/app/markets/components/markets.tsx @@ -1,5 +1,6 @@ 'use client'; import { useCallback, useEffect, useState } from 'react'; +import { useRouter, useSearchParams } from 'next/navigation'; import storage from 'local-storage-fallback'; import Header from '@/components/layout/header/Header'; import LoadingScreen from '@/components/Status/LoadingScreen'; @@ -33,11 +34,18 @@ const defaultStaredMarkets = JSON.parse( * that you want toLowerCase() render on the page. */ export default function Markets() { + const router = useRouter(); + const searchParams = useSearchParams(); + const { loading, data: rawMarkets } = useMarkets(); // token keys, aggregated with | for each "ERC20Token" object - const [selectedCollaterals, setSelectedCollaterals] = useState([]); - const [selectedLoanAssets, setSelectedLoanAssets] = useState([]); + const [selectedCollaterals, setSelectedCollaterals] = useState( + searchParams.get('collaterals')?.split(',').filter(Boolean) || [] + ); + const [selectedLoanAssets, setSelectedLoanAssets] = useState( + searchParams.get('loanAssets')?.split(',').filter(Boolean) || [] + ); // single choice: null for all networks const [selectedNetwork, setSelectedNetwork] = useState(null); @@ -92,6 +100,22 @@ export default function Markets() { } }, [rawMarkets]); + + const updateUrlParams = useCallback((collaterals: string[], loanAssets: string[]) => { + const params = new URLSearchParams(searchParams); + if (collaterals.length > 0) { + params.set('collaterals', collaterals.join(',')); + } else { + params.delete('collaterals'); + } + if (loanAssets.length > 0) { + params.set('loanAssets', loanAssets.join(',')); + } else { + params.delete('loanAssets'); + } + router.push(`?${params.toString()}`, { scroll: false }); + }, [router, searchParams]); + // Update the all markets pass to the table useEffect(() => { const filtered = applyFilterAndSort( @@ -105,6 +129,7 @@ export default function Markets() { selectedLoanAssets, ); setFilteredMarkets(filtered); + updateUrlParams(selectedCollaterals, selectedLoanAssets); }, [ rawMarkets, hideDust, @@ -114,6 +139,7 @@ export default function Markets() { selectedCollaterals, selectedLoanAssets, selectedNetwork, + updateUrlParams, ]); const titleOnclick = useCallback( @@ -129,6 +155,7 @@ export default function Markets() { [sortColumn, sortDirection], ); + return (
@@ -152,7 +179,10 @@ export default function Markets() { label="Loan Asset" placeholder="All loan asset" selectedAssets={selectedLoanAssets} - setSelectedAssets={setSelectedLoanAssets} + setSelectedAssets={(assets) => { + setSelectedLoanAssets(assets); + updateUrlParams(selectedCollaterals, assets); + }} items={uniqueLoanAssets} loading={loading} /> @@ -162,7 +192,10 @@ export default function Markets() { label="Collateral" placeholder="All collateral" selectedAssets={selectedCollaterals} - setSelectedAssets={setSelectedCollaterals} + setSelectedAssets={(assets) => { + setSelectedCollaterals(assets); + updateUrlParams(assets, selectedLoanAssets); + }} items={uniqueCollaterals} loading={loading} /> From 6d5b6b8cbbad776b60dccd8edbd3836e7a61d76e Mon Sep 17 00:00:00 2001 From: Anton Cheng Date: Tue, 22 Oct 2024 09:54:14 +0800 Subject: [PATCH 3/4] feat: filter advanced --- app/markets/components/AssetFilter.tsx | 27 ++++++-- app/markets/components/NetworkFilter.tsx | 4 +- app/markets/components/markets.tsx | 82 +++++++++++++++--------- 3 files changed, 79 insertions(+), 34 deletions(-) diff --git a/app/markets/components/AssetFilter.tsx b/app/markets/components/AssetFilter.tsx index cb9edb2e..2f9adde5 100644 --- a/app/markets/components/AssetFilter.tsx +++ b/app/markets/components/AssetFilter.tsx @@ -1,6 +1,6 @@ 'use client'; import { useState, useRef, useEffect, KeyboardEvent } from 'react'; -import { ChevronDownIcon, TrashIcon } from '@radix-ui/react-icons'; +import { ChevronDownIcon, TrashIcon, ExclamationTriangleIcon } from '@radix-ui/react-icons'; import Image from 'next/image'; import { ERC20Token, infoToKey } from '@/utils/tokens'; @@ -10,7 +10,7 @@ type FilterProps = { selectedAssets: string[]; setSelectedAssets: (assets: string[]) => void; items: ERC20Token[]; - loading?: boolean; // Made optional since it's not used + loading: boolean; }; export default function AssetFilter({ @@ -19,11 +19,23 @@ export default function AssetFilter({ selectedAssets, setSelectedAssets, items, + loading, }: FilterProps) { const [query, setQuery] = useState(''); const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); + // Check if the selected assets are invalid (not present in the items list) after loading is complete + const invalidSelection = + !loading && + selectedAssets.length > 0 && + selectedAssets.every( + (asset) => + !items.some( + (item) => item.networks.map((n) => infoToKey(n.address, n.chain.id)).join('|') === asset, + ), + ); + useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { @@ -80,7 +92,14 @@ export default function AssetFilter({ > {label}
- {selectedAssets.length > 0 ? ( + {loading ? ( + Loading... + ) : invalidSelection ? ( +
+ + Invalid +
+ ) : selectedAssets.length > 0 ? (
{selectedAssets.map((asset) => { const token = items.find( @@ -100,7 +119,7 @@ export default function AssetFilter({
- {isOpen && ( + {isOpen && !loading && (
void; }; -export default function NetworkFilter({ setSelectedNetwork }: FilterProps) { +export default function NetworkFilter({ setSelectedNetwork, selectedNetwork }: FilterProps) { return (