From e8d216b86dee87f5e72ef901572fff714ab5b6c6 Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 24 Feb 2024 00:13:23 +0800 Subject: [PATCH] :sparkles: Add initial multisig address page --- src/AddressPage.js | 45 ++++++++++++++++++++ src/App.js | 77 ++++++++++++++++++++++------------ src/IndexPage.js | 6 +-- src/Layout.js | 20 +++++---- src/NewAddressPage.js | 6 +-- src/components/DeleteButton.js | 6 +-- 6 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 src/AddressPage.js diff --git a/src/AddressPage.js b/src/AddressPage.js new file mode 100644 index 0000000..ad1ad0d --- /dev/null +++ b/src/AddressPage.js @@ -0,0 +1,45 @@ +import DeleteButton from "./components/DeleteButton.js"; +import { Button } from "flowbite-react"; + +export default function AddressPage({ address, deleteAddress, navigate }) { + return ( +
+

+ Multisig {address.args} +

+

+ Requiring {address.threshold}{" "} + {address.threshold === 1 ? "signature" : "signatures"} from{" "} + {address.signers.length}{" "} + {address.signers.length === 1 ? "signer" : "signers"}: +

+ +
    + {address.signers.map((signer, i) => ( +
  1. + {signer} +
  2. + ))} +
+ + {address.required > 0 ? ( +

+ Signatures from the first {address.required}{" "} + {address.required === 1 ? "signer" : "signers"} are required. +

+ ) : null} + +
+ + { + deleteAddress(address.args); + navigate("#/"); + }} + /> +
+
+ ); +} diff --git a/src/App.js b/src/App.js index 535f587..44038be 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,10 @@ +import { Spinner } from "flowbite-react"; import { Suspense, useCallback, useTransition } from "react"; import { useHash } from "react-use"; +import AddressPage from "./AddressPage.js"; import IndexPage from "./IndexPage.js"; -import NewAddressPage from "./NewAddressPage.js"; import Layout from "./Layout.js"; -import { Spinner } from "flowbite-react"; +import NewAddressPage from "./NewAddressPage.js"; import usePersistReducer from "./reducer.js"; function App() { @@ -14,7 +15,9 @@ function App() { ); } -const PREFIX_DUPLICATE_ADDRESS = "#/addresses/duplicate/"; +function findAddress(state, args) { + return state.addresses.find((address) => address.args === args); +} function Router() { const [page, setPage] = useHash(); @@ -23,30 +26,39 @@ function Router() { const navigate = useCallback((url) => startTransition(() => setPage(url))); - let content; - switch (page) { - case "": - case "#/": - content = ; - break; - case "#/addresses/new": - content = ; - break; - default: - if (page.startsWith(PREFIX_DUPLICATE_ADDRESS)) { - content = ( - + const fallbackRoute = () => ; + const staticRoutes = { + "#/": () => , + "#/addresses/new": () => , + }; + staticRoutes[""] = staticRoutes["#/"]; + const dynamicRoutes = [ + [ + "#/addresses/duplicate/", + (args) => ( + + ), + ], + [ + "#/addresses/", + (args) => { + const address = findAddress(state, args); + return address ? ( + + ) : ( + fallbackRoute() ); - } else { - content = ; - } - } + }, + ], + ]; + const content = dispatchRoute( + page, + staticRoutes, + dynamicRoutes, + fallbackRoute, + ); return {content}; } @@ -70,4 +82,17 @@ function NotFound({ navigate, page }) { ); } +function dispatchRoute(page, staticRoutes, dynamicRoutes, fallbackRoute) { + if (page in staticRoutes) { + return staticRoutes[page](); + } + for (const [prefix, creator] of dynamicRoutes) { + if (page.startsWith(prefix)) { + const path = page.slice(prefix.length).split("/"); + return creator(...path); + } + } + return fallbackRoute(); +} + export default App; diff --git a/src/IndexPage.js b/src/IndexPage.js index 4cd0525..d641fe7 100644 --- a/src/IndexPage.js +++ b/src/IndexPage.js @@ -4,14 +4,14 @@ import DeleteButton from "./components/DeleteButton.js"; function AddressesList({ navigate, addresses, deleteAddress }) { return (
-

Mulgisig Addresses

+

Mulgisig Addresses

    {addresses.map((address) => (
  • - + {address.args} deleteAddress(address.args)} /> diff --git a/src/Layout.js b/src/Layout.js index b495344..f9ec364 100644 --- a/src/Layout.js +++ b/src/Layout.js @@ -1,15 +1,17 @@ export default function Layout({ children, isPending }) { return (
    -
    - CKB Multisig CoBuild PoC -
    -
    {children}
    +
    +
    + CKB Multisig CoBuild PoC +
    +
    {children}
    +
    ); } diff --git a/src/NewAddressPage.js b/src/NewAddressPage.js index 4a133f7..5c9d331 100644 --- a/src/NewAddressPage.js +++ b/src/NewAddressPage.js @@ -39,7 +39,7 @@ function check(draft, formData) { } } -export default function NewAddressPage({ addAddress, navigate }) { +export default function NewAddressPage({ addAddress, navigate, template }) { const [state, dispatch] = useImmerReducer( (draft, action) => { switch (action.type) { @@ -64,7 +64,7 @@ export default function NewAddressPage({ addAddress, navigate }) { }, { error: null, - data: { + data: template ?? { args: "", threshold: 1, required: 0, @@ -93,7 +93,7 @@ export default function NewAddressPage({ addAddress, navigate }) { return (
    -

    Add Multisig Address

    +

    Add Multisig Address

    diff --git a/src/components/DeleteButton.js b/src/components/DeleteButton.js index d99c4e8..62db234 100644 --- a/src/components/DeleteButton.js +++ b/src/components/DeleteButton.js @@ -2,7 +2,7 @@ import { Button } from "flowbite-react"; import { useState } from "react"; import { HiOutlineTrash, HiOutlineX } from "react-icons/hi"; -export default function DeleteButton({ onClick, ...props }) { +export default function DeleteButton({ onClick, className, ...props }) { const [confirming, setConfirming] = useState(false); if (!confirming) { @@ -12,14 +12,14 @@ export default function DeleteButton({ onClick, ...props }) { onClick={() => setConfirming(true)} outline color="failure" - className="bg-slate-300" + className={`bg-slate-300 ${className}`} > Delete ); } else { return ( - +