|
17 | 17 | import DashboardSkeleton from "@requestnetwork/shared-components/dashboard-skeleton.svelte";
|
18 | 18 | import { toast } from "svelte-sonner";
|
19 | 19 | import Modal from "@requestnetwork/shared-components/modal.svelte";
|
| 20 | + import SearchableDropdownCheckbox from "@requestnetwork/shared-components/searchable-checkbox-dropdown.svelte"; |
20 | 21 | // Icons
|
21 | 22 | import ChevronDown from "@requestnetwork/shared-icons/chevron-down.svelte";
|
22 | 23 | import ChevronLeft from "@requestnetwork/shared-icons/chevron-left.svelte";
|
|
106 | 107 | let sortOrder = "desc";
|
107 | 108 | let sortColumn = "timestamp";
|
108 | 109 |
|
| 110 | + let selectedNetworks: string[] = []; |
| 111 | + let networkOptions: { value: string; checked: boolean }[] = []; |
| 112 | +
|
| 113 | + let selectedTxTypes: string[] = []; |
| 114 | + let txTypeOptions = [ |
| 115 | + { value: "IN", checked: false }, |
| 116 | + { value: "OUT", checked: false }, |
| 117 | + ]; |
| 118 | +
|
| 119 | + let selectedStatuses: string[] = []; |
| 120 | + let statusOptions = [ |
| 121 | + { value: "paid", checked: false }, |
| 122 | + { value: "partially paid", checked: false }, |
| 123 | + { value: "accepted", checked: false }, |
| 124 | + { value: "awaiting payment", checked: false }, |
| 125 | + { value: "canceled", checked: false }, |
| 126 | + { value: "rejected", checked: false }, |
| 127 | + { value: "overdue", checked: false }, |
| 128 | + { value: "pending", checked: false }, |
| 129 | + ]; |
| 130 | +
|
109 | 131 | const handleWalletConnection = async () => {
|
110 | 132 | account = getAccount(wagmiConfig);
|
111 | 133 | await loadRequests(sliderValueForDecryption, account, requestNetwork);
|
|
175 | 197 | type: Types.Identity.TYPE.ETHEREUM_ADDRESS,
|
176 | 198 | value: account?.address,
|
177 | 199 | });
|
| 200 | +
|
178 | 201 | requests = requestsData
|
179 | 202 | ?.map((request) => request.getData())
|
180 | 203 | .sort((a, b) => b.timestamp - a.timestamp);
|
| 204 | +
|
| 205 | + const uniqueNetworks = new Set<string>(); |
| 206 | + requests?.forEach((request) => { |
| 207 | + const network = request.currencyInfo.network; |
| 208 | + if (network) { |
| 209 | + uniqueNetworks.add(network); |
| 210 | + } |
| 211 | + }); |
| 212 | +
|
| 213 | + networkOptions = Array.from(uniqueNetworks).map((network) => ({ |
| 214 | + value: network, |
| 215 | + checked: selectedNetworks.includes(network), |
| 216 | + })); |
181 | 217 | } catch (error) {
|
182 | 218 | console.error("Failed to fetch requests:", error);
|
183 | 219 | } finally {
|
|
233 | 269 |
|
234 | 270 | $: filteredRequests = requests?.filter((request) => {
|
235 | 271 | const terms = searchQuery.toLowerCase();
|
| 272 | + const network = request.currencyInfo.network; |
| 273 | + const txType = signer === request.payer?.value ? "OUT" : "IN"; |
| 274 | + const status = checkStatus(request).toLowerCase(); |
| 275 | +
|
| 276 | + const networkMatch = |
| 277 | + selectedNetworks.length === 0 || |
| 278 | + (network && selectedNetworks.includes(network)); |
| 279 | +
|
| 280 | + const txTypeMatch = |
| 281 | + selectedTxTypes.length === 0 || selectedTxTypes.includes(txType); |
| 282 | +
|
| 283 | + const statusMatch = |
| 284 | + selectedStatuses.length === 0 || selectedStatuses.includes(status); |
236 | 285 |
|
237 | 286 | if (
|
238 |
| - currentTab === "All" || |
239 |
| - (currentTab === "Get Paid" && |
240 |
| - request.payee?.value?.toLowerCase() === signer?.toLowerCase()) || |
241 |
| - (currentTab === "Pay" && |
242 |
| - request.payer?.value?.toLowerCase() === signer?.toLowerCase()) |
| 287 | + networkMatch && |
| 288 | + txTypeMatch && |
| 289 | + statusMatch && |
| 290 | + (currentTab === "All" || |
| 291 | + (currentTab === "Get Paid" && |
| 292 | + request.payee?.value?.toLowerCase() === signer?.toLowerCase()) || |
| 293 | + (currentTab === "Pay" && |
| 294 | + request.payer?.value?.toLowerCase() === signer?.toLowerCase())) |
243 | 295 | ) {
|
244 | 296 | const invoiceMatches = request.contentData?.invoiceNumber
|
245 | 297 | ?.toString()
|
|
374 | 426 | const handleSearchChange = (event: Event) => {
|
375 | 427 | const { value } = event.target as HTMLInputElement;
|
376 | 428 | searchQuery = value;
|
| 429 | + currentPage = 1; |
377 | 430 | };
|
378 | 431 |
|
379 | 432 | const handleSort = (column: string) => {
|
|
410 | 463 | return;
|
411 | 464 |
|
412 | 465 | loading = true;
|
413 |
| - if (sliderValue === "on") { |
414 |
| - try { |
415 |
| - const signer = await getEthersSigner(wagmiConfig); |
416 |
| - if (signer && currentAccount?.address) { |
417 |
| - loadSessionSignatures = |
418 |
| - localStorage?.getItem("lit-wallet-sig") === null; |
419 |
| - await cipherProvider?.getSessionSignatures( |
420 |
| - signer, |
421 |
| - currentAccount.address, |
422 |
| - window.location.host, |
423 |
| - "Sign in to Lit Protocol through Request Network" |
424 |
| - ); |
425 |
| - cipherProvider?.enableDecryption(true); |
426 |
| - localStorage?.setItem("isDecryptionEnabled", JSON.stringify(true)); |
| 466 | + const previousNetworks = [...selectedNetworks]; // Store current selection |
| 467 | +
|
| 468 | + try { |
| 469 | + if (sliderValue === "on") { |
| 470 | + try { |
| 471 | + const signer = await getEthersSigner(wagmiConfig); |
| 472 | + if (signer && currentAccount?.address) { |
| 473 | + loadSessionSignatures = |
| 474 | + localStorage?.getItem("lit-wallet-sig") === null; |
| 475 | + await cipherProvider?.getSessionSignatures( |
| 476 | + signer, |
| 477 | + currentAccount.address, |
| 478 | + window.location.host, |
| 479 | + "Sign in to Lit Protocol through Request Network" |
| 480 | + ); |
| 481 | + cipherProvider?.enableDecryption(true); |
| 482 | + localStorage?.setItem("isDecryptionEnabled", JSON.stringify(true)); |
| 483 | + } |
| 484 | + } catch (error) { |
| 485 | + console.error("Failed to enable decryption:", error); |
| 486 | + toast.error("Failed to enable decryption."); |
| 487 | + return; |
| 488 | + } finally { |
| 489 | + loadSessionSignatures = false; |
427 | 490 | }
|
428 |
| - } catch (error) { |
429 |
| - console.error("Failed to enable decryption:", error); |
430 |
| - toast.error("Failed to enable decryption."); |
431 |
| - loading = false; |
432 |
| - return; |
433 |
| - } finally { |
434 |
| - loadSessionSignatures = false; |
| 491 | + } else { |
| 492 | + cipherProvider?.enableDecryption(false); |
| 493 | + localStorage?.setItem("isDecryptionEnabled", JSON.stringify(false)); |
435 | 494 | }
|
436 |
| - } else { |
437 |
| - cipherProvider?.enableDecryption(false); |
438 |
| - localStorage?.setItem("isDecryptionEnabled", JSON.stringify(false)); |
| 495 | + await getRequests(currentAccount, currentRequestNetwork); |
| 496 | + selectedNetworks = previousNetworks; // Restore selection |
| 497 | + } finally { |
| 498 | + loading = false; |
439 | 499 | }
|
440 |
| - await getRequests(currentAccount, currentRequestNetwork); |
441 |
| - loading = false; |
442 | 500 | };
|
443 | 501 |
|
444 | 502 | $: loadRequests(sliderValueForDecryption, account, requestNetwork);
|
| 503 | +
|
| 504 | + const handleNetworkSelection = async (networks: string[]) => { |
| 505 | + selectedNetworks = networks; |
| 506 | + currentPage = 1; |
| 507 | + if (networks.length === 0 && selectedNetworks.length > 0) { |
| 508 | + loading = true; |
| 509 | + try { |
| 510 | + await getRequests(account!, requestNetwork!); |
| 511 | + } finally { |
| 512 | + loading = false; |
| 513 | + } |
| 514 | + } |
| 515 | + }; |
| 516 | +
|
| 517 | + const handleTxTypeSelection = (types: string[]) => { |
| 518 | + selectedTxTypes = types; |
| 519 | + currentPage = 1; |
| 520 | + }; |
| 521 | +
|
| 522 | + const handleStatusSelection = (statuses: string[]) => { |
| 523 | + selectedStatuses = statuses; |
| 524 | + currentPage = 1; |
| 525 | + }; |
445 | 526 | </script>
|
446 | 527 |
|
447 | 528 | <div
|
|
485 | 566 | </div>
|
486 | 567 | <div style="display: flex; flex-direction: column;">
|
487 | 568 | <div class="search-wrapper">
|
488 |
| - <div class="search-wrapper" style="gap: 10px;"> |
489 |
| - <Input |
490 |
| - placeholder="Search..." |
491 |
| - width="w-[300px]" |
492 |
| - handleInput={handleSearchChange} |
493 |
| - > |
494 |
| - <div slot="icon"> |
495 |
| - <Search /> |
496 |
| - </div> |
497 |
| - </Input> |
498 |
| - {#if cipherProvider} |
499 |
| - <div class="width: fit-content;"> |
500 |
| - <Switch |
501 |
| - bind:value={sliderValueForDecryption} |
502 |
| - label="Show encrypted requests" |
503 |
| - fontSize={14} |
504 |
| - design="slider" |
505 |
| - /> |
506 |
| - </div> |
507 |
| - {/if} |
| 569 | + <Input |
| 570 | + placeholder="Search..." |
| 571 | + width="w-[300px]" |
| 572 | + handleInput={handleSearchChange} |
| 573 | + > |
| 574 | + <div slot="icon"> |
| 575 | + <Search /> |
| 576 | + </div> |
| 577 | + </Input> |
| 578 | + {#if cipherProvider} |
| 579 | + <div class="switch-wrapper"> |
| 580 | + <Switch |
| 581 | + bind:value={sliderValueForDecryption} |
| 582 | + label="Show encrypted requests" |
| 583 | + fontSize={14} |
| 584 | + design="slider" |
| 585 | + /> |
| 586 | + </div> |
| 587 | + {/if} |
| 588 | + |
| 589 | + <div class="dropdown-controls"> |
| 590 | + <SearchableDropdownCheckbox |
| 591 | + config={activeConfig} |
| 592 | + options={statusOptions} |
| 593 | + placeholder="Filter by Status" |
| 594 | + onchange={handleStatusSelection} |
| 595 | + searchPlaceholder="Search statuses..." |
| 596 | + type="status" |
| 597 | + /> |
| 598 | + <SearchableDropdownCheckbox |
| 599 | + config={activeConfig} |
| 600 | + options={txTypeOptions} |
| 601 | + placeholder="Filter by Type" |
| 602 | + onchange={handleTxTypeSelection} |
| 603 | + type="transaction" |
| 604 | + noSearch={true} |
| 605 | + /> |
| 606 | + <SearchableDropdownCheckbox |
| 607 | + config={activeConfig} |
| 608 | + options={networkOptions} |
| 609 | + placeholder="Filter by Chain" |
| 610 | + onchange={handleNetworkSelection} |
| 611 | + searchPlaceholder="Search chains..." |
| 612 | + type="network" |
| 613 | + /> |
| 614 | + <Dropdown |
| 615 | + config={activeConfig} |
| 616 | + type="checkbox" |
| 617 | + options={columnOptions} |
| 618 | + placeholder="Select Columns" |
| 619 | + onchange={handleColumnChange} |
| 620 | + /> |
508 | 621 | </div>
|
509 |
| - |
510 |
| - <Dropdown |
511 |
| - config={activeConfig} |
512 |
| - type="checkbox" |
513 |
| - options={columnOptions} |
514 |
| - placeholder="Select Columns" |
515 |
| - onchange={handleColumnChange} |
516 |
| - /> |
517 | 622 | </div>
|
518 | 623 | <div class="table-wrapper">
|
519 | 624 | <table>
|
|
921 | 1026 | display: flex;
|
922 | 1027 | justify-content: space-between;
|
923 | 1028 | align-items: center;
|
| 1029 | + margin-bottom: 12px; |
924 | 1030 | }
|
925 | 1031 |
|
926 | 1032 | @media only screen and (max-width: 880px) {
|
|
1107 | 1213 | margin-bottom: 0.5rem;
|
1108 | 1214 | color: #4b5563;
|
1109 | 1215 | }
|
| 1216 | +
|
| 1217 | + .dropdown-controls { |
| 1218 | + display: flex; |
| 1219 | + align-items: center; |
| 1220 | + margin-left: auto; |
| 1221 | + gap: 8px; |
| 1222 | + } |
| 1223 | +
|
| 1224 | + .switch-wrapper { |
| 1225 | + margin-left: 8px; |
| 1226 | + } |
1110 | 1227 | </style>
|
0 commit comments