From 2b49b23c45f28a737db1f30b1524b9f162f00ae5 Mon Sep 17 00:00:00 2001 From: Matthew O'Connell Date: Sun, 20 Aug 2023 23:54:07 +0200 Subject: [PATCH 1/7] chore: add .gitignore --- .gitignore | 2 ++ mist-invoice-contracts/.gitignore | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 .gitignore create mode 100644 mist-invoice-contracts/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b04422a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# IDE +.DS_Store \ No newline at end of file diff --git a/mist-invoice-contracts/.gitignore b/mist-invoice-contracts/.gitignore new file mode 100644 index 0000000..2915a47 --- /dev/null +++ b/mist-invoice-contracts/.gitignore @@ -0,0 +1,6 @@ +node_modules +.yarn +cache +out +src/types +.env \ No newline at end of file From 778cd29d4628eb06a024778e8f204b40fd8e4e74 Mon Sep 17 00:00:00 2001 From: Matthew O'Connell Date: Sun, 20 Aug 2023 23:54:52 +0200 Subject: [PATCH 2/7] refactor(dapp): rebuild w nextjs --- mist-invoice-dapp/.eslintrc.json | 3 + mist-invoice-dapp/.gitignore | 41 + mist-invoice-dapp/README.md | 34 + mist-invoice-dapp/jest.config.ts | 42 + mist-invoice-dapp/jest.setup.ts | 17 + mist-invoice-dapp/next.config.js | 4 + mist-invoice-dapp/package.json | 76 + mist-invoice-dapp/postcss.config.js | 6 + mist-invoice-dapp/public/next.svg | 1 + mist-invoice-dapp/public/vercel.svg | 1 + mist-invoice-dapp/src/app/_app.tsx | 36 + mist-invoice-dapp/src/app/favicon.ico | Bin 0 -> 25931 bytes mist-invoice-dapp/src/app/globals.css | 31 + mist-invoice-dapp/src/app/layout.tsx | 19 + mist-invoice-dapp/src/app/page.test.tsx | 21 + mist-invoice-dapp/src/app/page.tsx | 116 + .../src/components/AccountLink.tsx | 93 + .../src/components/Container.test.tsx | 11 + .../src/components/Container.tsx | 39 + .../src/components/ErrorHandler.test.tsx | 19 + .../src/components/ErrorHandler.tsx | 11 + .../src/components/InvoiceDashboardTable.tsx | 410 + .../src/components/Loader.test.tsx | 11 + mist-invoice-dapp/src/components/Loader.tsx | 29 + .../src/components/NavButton.test.tsx | 13 + .../src/components/NavButton.tsx | 24 + .../components/NetworkChangeAlertModal.tsx | 54 + .../src/components/OrderedInput.tsx | 366 + .../src/components/ProfileButton.test.tsx | 19 + .../src/components/ProfileButton.tsx | 111 + .../src/components/RegisterSuccess.tsx | 192 + mist-invoice-dapp/src/components/StepInfo.tsx | 71 + .../src/components/StyledButton.test.tsx | 11 + .../src/components/StyledButton.tsx | 25 + .../__snapshots__/Container.test.tsx.snap | 9 + .../__snapshots__/ErrorHandler.test.tsx.snap | 12 + .../__snapshots__/Loader.test.tsx.snap | 42 + .../__snapshots__/NavButton.test.tsx.snap | 10 + .../__snapshots__/ProfileButton.test.tsx.snap | 60 + .../__snapshots__/StyledButton.test.tsx.snap | 10 + mist-invoice-dapp/src/components/index.ts | 6 + .../src/components/instant/DepositFunds.tsx | 530 + .../components/instant/FormConfirmation.tsx | 123 + .../components/instant/PaymentDetailsForm.tsx | 182 + .../components/instant/ProjectDetailsForm.tsx | 123 + .../src/components/instant/WithdrawFunds.jsx | 129 + mist-invoice-dapp/src/config.ts | 114 + .../src/context/CreateContext.tsx | 433 + .../src/context/MistContext.test.tsx | 132 + mist-invoice-dapp/src/context/MistContext.tsx | 124 + .../src/context/SearchContext.tsx | 56 + .../src/context/Web3Context.test.tsx | 104 + mist-invoice-dapp/src/context/Web3Context.tsx | 174 + .../__snapshots__/MistContext.test.tsx.snap | 54 + .../__snapshots__/Web3Context.test.tsx.snap | 24 + .../context/create-hooks/useCreateEscrow.tsx | 71 + .../context/create-hooks/useCreateInstant.tsx | 49 + mist-invoice-dapp/src/context/index.ts | 1 + mist-invoice-dapp/src/dbconfig.ts | 29 + mist-invoice-dapp/src/graphql/client.ts | 14 + mist-invoice-dapp/src/graphql/fragments.ts | 75 + mist-invoice-dapp/src/graphql/getInvoice.ts | 32 + mist-invoice-dapp/src/graphql/index.ts | 3 + mist-invoice-dapp/src/graphql/manifest.json | 1 + mist-invoice-dapp/src/graphql/search.ts | 91 + mist-invoice-dapp/src/graphql/subgraph.ts | 2189 +++ mist-invoice-dapp/src/hooks/index.ts | 1 + .../src/hooks/useFetchTokensViaIPFS.ts | 44 + .../src/hooks/useInvoiceStatus.tsx | 104 + mist-invoice-dapp/src/icons/ArrowIcons.tsx | 35 + mist-invoice-dapp/src/icons/CopyIcon.tsx | 13 + mist-invoice-dapp/src/icons/FilterIcon.tsx | 16 + mist-invoice-dapp/src/icons/HamburgerIcon.tsx | 13 + mist-invoice-dapp/src/icons/QuestionIcon.tsx | 23 + mist-invoice-dapp/src/icons/VerticalDots.tsx | 7 + .../src/icons/WalletFilledIcon.tsx | 15 + .../pages/__snapshots__/Home.test.tsx.snap | 36 + .../SelectInvoiceType.test.tsx.snap | 86 + .../src/pages/create/index.test.tsx | 28 + mist-invoice-dapp/src/pages/create/index.tsx | 131 + .../src/pages/create/instant/index.tsx | 184 + .../src/pages/invoices/InvoicesStyles.tsx | 111 + .../src/pages/invoices/index.tsx | 102 + .../src/shared/ConnectWeb3.test.tsx | 11 + mist-invoice-dapp/src/shared/ConnectWeb3.tsx | 103 + mist-invoice-dapp/src/shared/Footer.test.tsx | 11 + mist-invoice-dapp/src/shared/Footer.tsx | 74 + mist-invoice-dapp/src/shared/Header.test.tsx | 21 + mist-invoice-dapp/src/shared/Header.tsx | 288 + mist-invoice-dapp/src/shared/Layout.test.tsx | 30 + mist-invoice-dapp/src/shared/Layout.tsx | 50 + .../__snapshots__/ConnectWeb3.test.tsx.snap | 46 + .../shared/__snapshots__/Footer.test.tsx.snap | 60 + .../shared/__snapshots__/Header.test.tsx.snap | 90 + .../shared/__snapshots__/Layout.test.tsx.snap | 151 + mist-invoice-dapp/src/theme.ts | 95 + mist-invoice-dapp/src/types/IArbitrable.ts | 142 + mist-invoice-dapp/src/types/IArbitrator.ts | 320 + mist-invoice-dapp/src/types/IERC20.ts | 286 + .../src/types/IMistPool.sol/IMISTPool.ts | 274 + .../src/types/IMistPool.sol/index.ts | 4 + mist-invoice-dapp/src/types/IMulticall3.ts | 416 + mist-invoice-dapp/src/types/ISmartInvoice.ts | 97 + .../src/types/ISmartInvoiceEscrow.ts | 267 + .../src/types/ISmartInvoiceFactory.ts | 184 + .../src/types/ISmartInvoiceInstant.ts | 162 + mist-invoice-dapp/src/types/IWRAPPED.ts | 84 + .../MistInvoiceEscrowTest.ts | 932 + .../MistInvoiceEscrowWrapper.t.sol/index.ts | 4 + .../src/types/MistInvoiceEscrowWrapper.ts | 277 + mist-invoice-dapp/src/types/Script.ts | 84 + mist-invoice-dapp/src/types/StdAssertions.ts | 769 + .../src/types/StdError.sol/StdError.ts | 199 + .../src/types/StdError.sol/index.ts | 4 + mist-invoice-dapp/src/types/StdInvariant.ts | 212 + .../types/StdStorage.sol/StdStorageSafe.ts | 153 + .../src/types/StdStorage.sol/index.ts | 4 + mist-invoice-dapp/src/types/Vm.sol/Vm.ts | 3537 ++++ mist-invoice-dapp/src/types/Vm.sol/VmSafe.ts | 2218 +++ mist-invoice-dapp/src/types/Vm.sol/index.ts | 5 + mist-invoice-dapp/src/types/common.ts | 129 + .../InvoiceCreationScript.ts | 123 + .../types/createMistInvoice.s.sol/index.ts | 4 + .../DeployScript.ts | 91 + .../index.ts | 4 + .../types/factories/IArbitrable__factory.ts | 62 + .../types/factories/IArbitrator__factory.ts | 223 + .../src/types/factories/IERC20__factory.ts | 241 + .../IMistPool.sol/IMISTPool__factory.ts | 316 + .../types/factories/IMistPool.sol/index.ts | 4 + .../types/factories/IMulticall3__factory.ts | 457 + .../factories/ISmartInvoiceEscrow__factory.ts | 245 + .../ISmartInvoiceFactory__factory.ts | 145 + .../ISmartInvoiceInstant__factory.ts | 103 + .../types/factories/ISmartInvoice__factory.ts | 45 + .../src/types/factories/IWRAPPED__factory.ts | 26 + .../MistInvoiceEscrowTest__factory.ts | 618 + .../MistInvoiceEscrowWrapper.t.sol/index.ts | 4 + .../MistInvoiceEscrowWrapper__factory.ts | 296 + .../src/types/factories/Script__factory.ts | 32 + .../types/factories/StdAssertions__factory.ts | 412 + .../StdError.sol/StdError__factory.ts | 178 + .../src/types/factories/StdError.sol/index.ts | 4 + .../types/factories/StdInvariant__factory.ts | 150 + .../StdStorage.sol/StdStorageSafe__factory.ts | 117 + .../types/factories/StdStorage.sol/index.ts | 4 + .../types/factories/Vm.sol/VmSafe__factory.ts | 2695 +++ .../src/types/factories/Vm.sol/Vm__factory.ts | 3895 +++++ .../src/types/factories/Vm.sol/index.ts | 5 + .../InvoiceCreationScript__factory.ts | 119 + .../createMistInvoice.s.sol/index.ts | 4 + .../DeployScript__factory.ts | 87 + .../index.ts | 4 + .../src/types/factories/index.ts | 24 + .../factories/test.sol/DSTest__factory.ts | 355 + .../types/factories/test.sol/Test__factory.ts | 537 + .../src/types/factories/test.sol/index.ts | 5 + mist-invoice-dapp/src/types/index.ts | 66 + .../src/types/test.sol/DSTest.ts | 614 + mist-invoice-dapp/src/types/test.sol/Test.ts | 905 + mist-invoice-dapp/src/types/test.sol/index.ts | 5 + mist-invoice-dapp/src/utils/3box.ts | 47 + .../src/utils/compatibilityHelpers.ts | 7 + mist-invoice-dapp/src/utils/constants.ts | 253 + mist-invoice-dapp/src/utils/erc20.ts | 13 + mist-invoice-dapp/src/utils/helpers.ts | 280 + mist-invoice-dapp/src/utils/index.ts | 6 + mist-invoice-dapp/src/utils/invoice.ts | 234 + mist-invoice-dapp/tailwind.config.ts | 20 + mist-invoice-dapp/tsconfig.json | 27 + mist-invoice-dapp/yarn.lock | 14106 ++++++++++++++++ 171 files changed, 47922 insertions(+) create mode 100644 mist-invoice-dapp/.eslintrc.json create mode 100644 mist-invoice-dapp/.gitignore create mode 100644 mist-invoice-dapp/README.md create mode 100644 mist-invoice-dapp/jest.config.ts create mode 100644 mist-invoice-dapp/jest.setup.ts create mode 100644 mist-invoice-dapp/next.config.js create mode 100644 mist-invoice-dapp/package.json create mode 100644 mist-invoice-dapp/postcss.config.js create mode 100644 mist-invoice-dapp/public/next.svg create mode 100644 mist-invoice-dapp/public/vercel.svg create mode 100644 mist-invoice-dapp/src/app/_app.tsx create mode 100644 mist-invoice-dapp/src/app/favicon.ico create mode 100644 mist-invoice-dapp/src/app/globals.css create mode 100644 mist-invoice-dapp/src/app/layout.tsx create mode 100644 mist-invoice-dapp/src/app/page.test.tsx create mode 100644 mist-invoice-dapp/src/app/page.tsx create mode 100644 mist-invoice-dapp/src/components/AccountLink.tsx create mode 100644 mist-invoice-dapp/src/components/Container.test.tsx create mode 100644 mist-invoice-dapp/src/components/Container.tsx create mode 100644 mist-invoice-dapp/src/components/ErrorHandler.test.tsx create mode 100644 mist-invoice-dapp/src/components/ErrorHandler.tsx create mode 100644 mist-invoice-dapp/src/components/InvoiceDashboardTable.tsx create mode 100644 mist-invoice-dapp/src/components/Loader.test.tsx create mode 100644 mist-invoice-dapp/src/components/Loader.tsx create mode 100644 mist-invoice-dapp/src/components/NavButton.test.tsx create mode 100644 mist-invoice-dapp/src/components/NavButton.tsx create mode 100644 mist-invoice-dapp/src/components/NetworkChangeAlertModal.tsx create mode 100644 mist-invoice-dapp/src/components/OrderedInput.tsx create mode 100644 mist-invoice-dapp/src/components/ProfileButton.test.tsx create mode 100644 mist-invoice-dapp/src/components/ProfileButton.tsx create mode 100644 mist-invoice-dapp/src/components/RegisterSuccess.tsx create mode 100644 mist-invoice-dapp/src/components/StepInfo.tsx create mode 100644 mist-invoice-dapp/src/components/StyledButton.test.tsx create mode 100644 mist-invoice-dapp/src/components/StyledButton.tsx create mode 100644 mist-invoice-dapp/src/components/__snapshots__/Container.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/__snapshots__/ErrorHandler.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/__snapshots__/Loader.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/__snapshots__/NavButton.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/__snapshots__/ProfileButton.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/__snapshots__/StyledButton.test.tsx.snap create mode 100644 mist-invoice-dapp/src/components/index.ts create mode 100644 mist-invoice-dapp/src/components/instant/DepositFunds.tsx create mode 100644 mist-invoice-dapp/src/components/instant/FormConfirmation.tsx create mode 100644 mist-invoice-dapp/src/components/instant/PaymentDetailsForm.tsx create mode 100644 mist-invoice-dapp/src/components/instant/ProjectDetailsForm.tsx create mode 100644 mist-invoice-dapp/src/components/instant/WithdrawFunds.jsx create mode 100644 mist-invoice-dapp/src/config.ts create mode 100644 mist-invoice-dapp/src/context/CreateContext.tsx create mode 100644 mist-invoice-dapp/src/context/MistContext.test.tsx create mode 100644 mist-invoice-dapp/src/context/MistContext.tsx create mode 100644 mist-invoice-dapp/src/context/SearchContext.tsx create mode 100644 mist-invoice-dapp/src/context/Web3Context.test.tsx create mode 100644 mist-invoice-dapp/src/context/Web3Context.tsx create mode 100644 mist-invoice-dapp/src/context/__snapshots__/MistContext.test.tsx.snap create mode 100644 mist-invoice-dapp/src/context/__snapshots__/Web3Context.test.tsx.snap create mode 100644 mist-invoice-dapp/src/context/create-hooks/useCreateEscrow.tsx create mode 100644 mist-invoice-dapp/src/context/create-hooks/useCreateInstant.tsx create mode 100644 mist-invoice-dapp/src/context/index.ts create mode 100644 mist-invoice-dapp/src/dbconfig.ts create mode 100644 mist-invoice-dapp/src/graphql/client.ts create mode 100644 mist-invoice-dapp/src/graphql/fragments.ts create mode 100644 mist-invoice-dapp/src/graphql/getInvoice.ts create mode 100644 mist-invoice-dapp/src/graphql/index.ts create mode 100644 mist-invoice-dapp/src/graphql/manifest.json create mode 100644 mist-invoice-dapp/src/graphql/search.ts create mode 100644 mist-invoice-dapp/src/graphql/subgraph.ts create mode 100644 mist-invoice-dapp/src/hooks/index.ts create mode 100644 mist-invoice-dapp/src/hooks/useFetchTokensViaIPFS.ts create mode 100644 mist-invoice-dapp/src/hooks/useInvoiceStatus.tsx create mode 100644 mist-invoice-dapp/src/icons/ArrowIcons.tsx create mode 100644 mist-invoice-dapp/src/icons/CopyIcon.tsx create mode 100644 mist-invoice-dapp/src/icons/FilterIcon.tsx create mode 100644 mist-invoice-dapp/src/icons/HamburgerIcon.tsx create mode 100644 mist-invoice-dapp/src/icons/QuestionIcon.tsx create mode 100644 mist-invoice-dapp/src/icons/VerticalDots.tsx create mode 100644 mist-invoice-dapp/src/icons/WalletFilledIcon.tsx create mode 100644 mist-invoice-dapp/src/pages/__snapshots__/Home.test.tsx.snap create mode 100644 mist-invoice-dapp/src/pages/__snapshots__/SelectInvoiceType.test.tsx.snap create mode 100644 mist-invoice-dapp/src/pages/create/index.test.tsx create mode 100644 mist-invoice-dapp/src/pages/create/index.tsx create mode 100644 mist-invoice-dapp/src/pages/create/instant/index.tsx create mode 100644 mist-invoice-dapp/src/pages/invoices/InvoicesStyles.tsx create mode 100644 mist-invoice-dapp/src/pages/invoices/index.tsx create mode 100644 mist-invoice-dapp/src/shared/ConnectWeb3.test.tsx create mode 100644 mist-invoice-dapp/src/shared/ConnectWeb3.tsx create mode 100644 mist-invoice-dapp/src/shared/Footer.test.tsx create mode 100644 mist-invoice-dapp/src/shared/Footer.tsx create mode 100644 mist-invoice-dapp/src/shared/Header.test.tsx create mode 100644 mist-invoice-dapp/src/shared/Header.tsx create mode 100644 mist-invoice-dapp/src/shared/Layout.test.tsx create mode 100644 mist-invoice-dapp/src/shared/Layout.tsx create mode 100644 mist-invoice-dapp/src/shared/__snapshots__/ConnectWeb3.test.tsx.snap create mode 100644 mist-invoice-dapp/src/shared/__snapshots__/Footer.test.tsx.snap create mode 100644 mist-invoice-dapp/src/shared/__snapshots__/Header.test.tsx.snap create mode 100644 mist-invoice-dapp/src/shared/__snapshots__/Layout.test.tsx.snap create mode 100644 mist-invoice-dapp/src/theme.ts create mode 100644 mist-invoice-dapp/src/types/IArbitrable.ts create mode 100644 mist-invoice-dapp/src/types/IArbitrator.ts create mode 100644 mist-invoice-dapp/src/types/IERC20.ts create mode 100644 mist-invoice-dapp/src/types/IMistPool.sol/IMISTPool.ts create mode 100644 mist-invoice-dapp/src/types/IMistPool.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/IMulticall3.ts create mode 100644 mist-invoice-dapp/src/types/ISmartInvoice.ts create mode 100644 mist-invoice-dapp/src/types/ISmartInvoiceEscrow.ts create mode 100644 mist-invoice-dapp/src/types/ISmartInvoiceFactory.ts create mode 100644 mist-invoice-dapp/src/types/ISmartInvoiceInstant.ts create mode 100644 mist-invoice-dapp/src/types/IWRAPPED.ts create mode 100644 mist-invoice-dapp/src/types/MistInvoiceEscrowWrapper.t.sol/MistInvoiceEscrowTest.ts create mode 100644 mist-invoice-dapp/src/types/MistInvoiceEscrowWrapper.t.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/MistInvoiceEscrowWrapper.ts create mode 100644 mist-invoice-dapp/src/types/Script.ts create mode 100644 mist-invoice-dapp/src/types/StdAssertions.ts create mode 100644 mist-invoice-dapp/src/types/StdError.sol/StdError.ts create mode 100644 mist-invoice-dapp/src/types/StdError.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/StdInvariant.ts create mode 100644 mist-invoice-dapp/src/types/StdStorage.sol/StdStorageSafe.ts create mode 100644 mist-invoice-dapp/src/types/StdStorage.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/Vm.sol/Vm.ts create mode 100644 mist-invoice-dapp/src/types/Vm.sol/VmSafe.ts create mode 100644 mist-invoice-dapp/src/types/Vm.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/common.ts create mode 100644 mist-invoice-dapp/src/types/createMistInvoice.s.sol/InvoiceCreationScript.ts create mode 100644 mist-invoice-dapp/src/types/createMistInvoice.s.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/deployMistInvoiceEscrowWrapper.s.sol/DeployScript.ts create mode 100644 mist-invoice-dapp/src/types/deployMistInvoiceEscrowWrapper.s.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/IArbitrable__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/IArbitrator__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/IERC20__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/IMistPool.sol/IMISTPool__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/IMistPool.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/IMulticall3__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/ISmartInvoiceEscrow__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/ISmartInvoiceFactory__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/ISmartInvoiceInstant__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/ISmartInvoice__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/IWRAPPED__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/MistInvoiceEscrowWrapper.t.sol/MistInvoiceEscrowTest__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/MistInvoiceEscrowWrapper.t.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/MistInvoiceEscrowWrapper__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/Script__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdAssertions__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdError.sol/StdError__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdError.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdInvariant__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdStorage.sol/StdStorageSafe__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/StdStorage.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/Vm.sol/VmSafe__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/Vm.sol/Vm__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/Vm.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/createMistInvoice.s.sol/InvoiceCreationScript__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/createMistInvoice.s.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/deployMistInvoiceEscrowWrapper.s.sol/DeployScript__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/deployMistInvoiceEscrowWrapper.s.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/index.ts create mode 100644 mist-invoice-dapp/src/types/factories/test.sol/DSTest__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/test.sol/Test__factory.ts create mode 100644 mist-invoice-dapp/src/types/factories/test.sol/index.ts create mode 100644 mist-invoice-dapp/src/types/index.ts create mode 100644 mist-invoice-dapp/src/types/test.sol/DSTest.ts create mode 100644 mist-invoice-dapp/src/types/test.sol/Test.ts create mode 100644 mist-invoice-dapp/src/types/test.sol/index.ts create mode 100644 mist-invoice-dapp/src/utils/3box.ts create mode 100644 mist-invoice-dapp/src/utils/compatibilityHelpers.ts create mode 100644 mist-invoice-dapp/src/utils/constants.ts create mode 100644 mist-invoice-dapp/src/utils/erc20.ts create mode 100644 mist-invoice-dapp/src/utils/helpers.ts create mode 100644 mist-invoice-dapp/src/utils/index.ts create mode 100644 mist-invoice-dapp/src/utils/invoice.ts create mode 100644 mist-invoice-dapp/tailwind.config.ts create mode 100644 mist-invoice-dapp/tsconfig.json create mode 100644 mist-invoice-dapp/yarn.lock diff --git a/mist-invoice-dapp/.eslintrc.json b/mist-invoice-dapp/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/mist-invoice-dapp/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/mist-invoice-dapp/.gitignore b/mist-invoice-dapp/.gitignore new file mode 100644 index 0000000..e45f92a --- /dev/null +++ b/mist-invoice-dapp/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js + +# testing +coverage + +# next.js +.next/ +out/ + +# production +build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# yarn +.yarn + +# IDE +.DS_Store diff --git a/mist-invoice-dapp/README.md b/mist-invoice-dapp/README.md new file mode 100644 index 0000000..f4da3c4 --- /dev/null +++ b/mist-invoice-dapp/README.md @@ -0,0 +1,34 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/mist-invoice-dapp/jest.config.ts b/mist-invoice-dapp/jest.config.ts new file mode 100644 index 0000000..ccbb0b5 --- /dev/null +++ b/mist-invoice-dapp/jest.config.ts @@ -0,0 +1,42 @@ +import type { JestConfigWithTsJest } from "ts-jest"; + +const jestConfig: JestConfigWithTsJest = { + preset: "ts-jest", + testEnvironment: "jsdom", + coveragePathIgnorePatterns: [ + "node_modules", + "src/utils/constants.ts", + "src/index.tsx", + "src/reportWebVitals.ts" + ], + coverageThreshold: { + global: { + branches: 50, + functions: 50, + lines: 50, + statements: 50 + } + }, + setupFilesAfterEnv: ["/jest.setup.ts"], + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + tsconfig: { + jsx: "react" + } //"tsconfig.test.json" + } + ], + "node_modules/preact/.+\\.(j|t)sx?$": [ + "ts-jest", + { + tsconfig: { + jsx: "react" + } + } + ] + }, + transformIgnorePatterns: ["node_modules/(?!preact)"] +}; + +export default jestConfig; diff --git a/mist-invoice-dapp/jest.setup.ts b/mist-invoice-dapp/jest.setup.ts new file mode 100644 index 0000000..6082610 --- /dev/null +++ b/mist-invoice-dapp/jest.setup.ts @@ -0,0 +1,17 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import "@testing-library/jest-dom"; +import { TextEncoder } from "util"; + +global.TextEncoder = TextEncoder; +global.matchMedia = + global.matchMedia || + function () { + return { + matches: false, + addListener: function () {}, + removeListener: function () {}, + }; + }; diff --git a/mist-invoice-dapp/next.config.js b/mist-invoice-dapp/next.config.js new file mode 100644 index 0000000..767719f --- /dev/null +++ b/mist-invoice-dapp/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +module.exports = nextConfig diff --git a/mist-invoice-dapp/package.json b/mist-invoice-dapp/package.json new file mode 100644 index 0000000..361831d --- /dev/null +++ b/mist-invoice-dapp/package.json @@ -0,0 +1,76 @@ +{ + "name": "test-next-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "test": "jest --coverage --watchAll", + "graphql-codegen": "codegen-graph-ts pull https://api.thegraph.com/subgraphs/name/psparacino/xdai-smart-invoices > ./src/graphql/manifest.json && codegen-graph-ts gen -s ./src/graphql/manifest.json -o ./src/graphql/subgraph.ts" + }, + "dependencies": { + "@chakra-ui/icon": "^3.1.0", + "@chakra-ui/react": "^2.8.0", + "@chakra-ui/styled-system": "^2.9.1", + "@chakra-ui/system": "^2.6.0", + "@chakra-ui/theme": "^3.2.0", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@ethersproject/address": "^5.7.0", + "@gnosis.pm/safe-apps-sdk": "^7.8.0", + "@gnosis.pm/safe-apps-web3modal": "^17.0.4", + "@openzeppelin/merkle-tree": "^1.0.5", + "@synthetixio/wei": "^2.74.4", + "@types/node": "20.5.1", + "@types/react": "18.2.20", + "@types/react-dom": "18.2.7", + "@walletconnect/encoding": "^1.0.2", + "@walletconnect/web3-provider": "^1.8.0", + "autoprefixer": "10.4.15", + "bufferutil": "^4.0.7", + "crypto-js": "^4.1.1", + "encoding": "^0.1.13", + "eslint": "8.47.0", + "eslint-config-next": "13.4.19", + "ethers": "^6.7.1", + "framer-motion": "^10.16.0", + "graphql-scalars": "^1.22.2", + "jest-environment-jsdom": "^29.6.2", + "next": "13.4.19", + "postcss": "8.4.28", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-error-boundary": "^4.0.11", + "react-indexed-db-hook": "^1.0.14", + "react-is": "^18.2.0", + "react-no-ssr": "^1.1.0", + "react-table": "^7.8.0", + "styled-components": "^6.0.7", + "tailwindcss": "3.3.3", + "ts-jest": "^29.1.1", + "tslib": "^2.6.2", + "typescript": "5.1.6", + "urql": "^4.0.5", + "utf-8-validate": "^6.0.3", + "web3": "^4.1.0", + "web3modal": "^1.9.12" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.0.1", + "@testing-library/react": "^14.0.0", + "@types/jest": "^29.5.3", + "@types/react-no-ssr": "^1.1.3", + "@types/react-table": "^7.7.14", + "@typescript-eslint/eslint-plugin": "^6.4.0", + "@typescript-eslint/parser": "^6.4.0", + "codegen-graph-ts": "^0.1.4", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "graphql": "^16.8.0", + "jest": "^29.6.2", + "prettier": "^3.0.2", + "ts-node": "^10.9.1" + } +} diff --git a/mist-invoice-dapp/postcss.config.js b/mist-invoice-dapp/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/mist-invoice-dapp/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/mist-invoice-dapp/public/next.svg b/mist-invoice-dapp/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/mist-invoice-dapp/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/mist-invoice-dapp/public/vercel.svg b/mist-invoice-dapp/public/vercel.svg new file mode 100644 index 0000000..d2f8422 --- /dev/null +++ b/mist-invoice-dapp/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/mist-invoice-dapp/src/app/_app.tsx b/mist-invoice-dapp/src/app/_app.tsx new file mode 100644 index 0000000..0ebd91b --- /dev/null +++ b/mist-invoice-dapp/src/app/_app.tsx @@ -0,0 +1,36 @@ +// import "./App.css"; +import App, { AppContext, AppInitialProps, AppProps } from "next/app"; +import { ChakraProvider, ColorModeScript, CSSReset } from "@chakra-ui/react"; +import theme from "@chakra-ui/theme"; +import { Global } from "@emotion/react"; +import React from "react"; +import { ErrorBoundary } from "react-error-boundary"; +import { initDB } from "react-indexed-db-hook"; + +import { ErrorHandler } from "../components/ErrorHandler"; +import { Web3ContextProvider } from "../context"; +import { MistContextProvider } from "../context/MistContext"; +import { DBConfig } from "../dbconfig"; +import { Layout } from "../shared/Layout"; +import { globalStyles } from "../theme"; + +initDB(DBConfig); + +const MistApp = ({ Component, pageProps }: AppProps) => ( + + + + + + + + {/* */} + + {/* */} + + + + +); + +export default MistApp; diff --git a/mist-invoice-dapp/src/app/favicon.ico b/mist-invoice-dapp/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/mist-invoice-dapp/src/app/globals.css b/mist-invoice-dapp/src/app/globals.css new file mode 100644 index 0000000..20da37e --- /dev/null +++ b/mist-invoice-dapp/src/app/globals.css @@ -0,0 +1,31 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/mist-invoice-dapp/src/app/layout.tsx b/mist-invoice-dapp/src/app/layout.tsx new file mode 100644 index 0000000..bd6f806 --- /dev/null +++ b/mist-invoice-dapp/src/app/layout.tsx @@ -0,0 +1,19 @@ +import "./globals.css"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "MIST Smart Invoice", + description: "Private invoice management", +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/mist-invoice-dapp/src/app/page.test.tsx b/mist-invoice-dapp/src/app/page.test.tsx new file mode 100644 index 0000000..b26e3d4 --- /dev/null +++ b/mist-invoice-dapp/src/app/page.test.tsx @@ -0,0 +1,21 @@ +import { render } from "@testing-library/react"; +import React from "react"; +import Home from "../pages/Home"; + +jest.mock("@chakra-ui/react", () => ({ + ...jest.requireActual("@chakra-ui/react"), + useBreakpointValue: () => "md", +})); +jest.mock("next/router", () => ({ + useRouter: () => ({ + push: jest.fn(), + }), +})); + +describe("Home", () => { + it("should render", () => { + const view = render(); + + expect(view.asFragment()).toMatchSnapshot(); + }); +}); diff --git a/mist-invoice-dapp/src/app/page.tsx b/mist-invoice-dapp/src/app/page.tsx new file mode 100644 index 0000000..0e9896c --- /dev/null +++ b/mist-invoice-dapp/src/app/page.tsx @@ -0,0 +1,116 @@ +"use client"; +import { + Button, + Flex, + Heading, + Text, + useBreakpointValue, +} from "@chakra-ui/react"; +import React, { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; + +import { useWeb3 } from "../context"; +import { logError } from "../utils"; + +const Home = () => { + const { connectAccount, account } = useWeb3(); + const router = useRouter(); + const [isMobile, setIsMobile] = useState(false); + const [buttonSize, setButtonSize] = useState("lg"); + + // const _buttonSize = useBreakpointValue({ base: "sm", sm: "md", md: "lg" }); + // setButtonSize(_buttonSize); + + useEffect(() => { + if (window) { + toggleMobileMode(); + window.addEventListener("resize", toggleMobileMode); + } + }); + + const toggleMobileMode = () => { + if (window.innerWidth < 600) { + setIsMobile(true); + } else { + setIsMobile(false); + } + }; + + const createInvoice = async () => { + if (account) { + router.push("/create"); + } else { + try { + await connectAccount(); + router.push("/create"); + } catch { + logError("Couldn't connect web3 wallet"); + } + } + }; + + const viewInvoices = async () => { + if (account) { + router.push("/invoices"); + } else { + try { + await connectAccount(); + router.push("/invoices"); + } catch { + logError("Couldn't connect web3 wallet"); + } + } + }; + + return ( + + + Welcome to Smart Invoice + + + How do you want to get started? + + + + + + + ); +}; + +export default Home; diff --git a/mist-invoice-dapp/src/components/AccountLink.tsx b/mist-invoice-dapp/src/components/AccountLink.tsx new file mode 100644 index 0000000..6c8d425 --- /dev/null +++ b/mist-invoice-dapp/src/components/AccountLink.tsx @@ -0,0 +1,93 @@ +import { Flex, Link, Text } from "@chakra-ui/react"; +import { isAddress } from "@ethersproject/address"; +import React, { useContext, useEffect, useState } from "react"; + +import { Web3Context } from "../context/Web3Context"; +import { theme } from "../theme"; +import { + getProfile, + getAddressLink, + getResolverInfo, + getResolverString, + isKnownResolver, +} from "../utils"; + +export type AccountLinkProps = { + address: string; + chainId?: number; +}; + +export const AccountLink: React.FC = ({ + address: inputAddress, + chainId: inputChainId, +}) => { + const { chainId: walletChainId } = useContext(Web3Context); + const address = inputAddress.toLowerCase(); + const [profile, setProfile] = useState(); + const chainId = inputChainId || walletChainId; + const isResolver = isKnownResolver(chainId, address); + + useEffect(() => { + let isSubscribed = true; + if (!isResolver && isAddress(address)) { + getProfile(address).then((p) => + isSubscribed ? setProfile(p) : undefined + ); + } + return () => { + isSubscribed = false; + }; + }, [address, isResolver]); + + let displayString = getResolverString(chainId, address); + + let imageUrl = isResolver + ? getResolverInfo(chainId, address).logoUrl + : undefined; + + if (!isResolver && profile) { + if (profile.name) { + displayString = profile.name; + } + if (profile.imageUrl) { + imageUrl = profile.imageUrl; + } + } + + return ( + + + + {displayString} + + + ); +}; diff --git a/mist-invoice-dapp/src/components/Container.test.tsx b/mist-invoice-dapp/src/components/Container.test.tsx new file mode 100644 index 0000000..dde4ead --- /dev/null +++ b/mist-invoice-dapp/src/components/Container.test.tsx @@ -0,0 +1,11 @@ +import { render } from "@testing-library/react"; +import React from "react"; +import { Container } from "./Container"; + +describe("Container", () => { + it("should render", () => { + const view = render(); + + expect(view.asFragment()).toMatchSnapshot(); + }); +}); diff --git a/mist-invoice-dapp/src/components/Container.tsx b/mist-invoice-dapp/src/components/Container.tsx new file mode 100644 index 0000000..31593fd --- /dev/null +++ b/mist-invoice-dapp/src/components/Container.tsx @@ -0,0 +1,39 @@ +import { Flex } from "@chakra-ui/react"; +import React from "react"; + +import { isBackdropFilterSupported } from "../utils"; + +export type ContainerProps = { + overlay?: boolean; +}; + +export const Container: React.FC> = ({ + children, + overlay, + ...props +}) => { + const overlayStyles = isBackdropFilterSupported() + ? { + backgroundColor: "black30", + backdropFilter: "blur(8px)", + } + : { + backgroundColor: "black80", + }; + + return ( + + {children} + + ); +}; diff --git a/mist-invoice-dapp/src/components/ErrorHandler.test.tsx b/mist-invoice-dapp/src/components/ErrorHandler.test.tsx new file mode 100644 index 0000000..49caaa7 --- /dev/null +++ b/mist-invoice-dapp/src/components/ErrorHandler.test.tsx @@ -0,0 +1,19 @@ +import { render } from "@testing-library/react"; +import React from "react"; +import { ErrorHandler } from "./ErrorHandler"; + +describe("ErrorHandler", () => { + const mockResetErrorBoundary = jest.fn(); + + it("should render", () => { + const error = new Error("Test error"); + const view = render( + , + ); + + expect(view.asFragment()).toMatchSnapshot(); + }); +}); diff --git a/mist-invoice-dapp/src/components/ErrorHandler.tsx b/mist-invoice-dapp/src/components/ErrorHandler.tsx new file mode 100644 index 0000000..c60def0 --- /dev/null +++ b/mist-invoice-dapp/src/components/ErrorHandler.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import { FallbackProps } from "react-error-boundary"; + +export const ErrorHandler: React.FC = ({ + error, +}) => ( + <> +

Error

+
{error.message}
+ +); diff --git a/mist-invoice-dapp/src/components/InvoiceDashboardTable.tsx b/mist-invoice-dapp/src/components/InvoiceDashboardTable.tsx new file mode 100644 index 0000000..9653adb --- /dev/null +++ b/mist-invoice-dapp/src/components/InvoiceDashboardTable.tsx @@ -0,0 +1,410 @@ +import { + Button, + Flex, + Text, + Heading, + IconButton, + Image as ChakraImage, + chakra, + Link, + Menu, + MenuButton, + MenuList, + MenuItem, + HStack, + Badge, +} from "@chakra-ui/react"; +import { formatUnits } from "ethers"; +import React, { useMemo } from "react"; +import { useTable, useSortBy, usePagination } from "react-table"; +import { Loader } from "./Loader"; +import { useInvoiceStatus } from "../hooks/useInvoiceStatus"; +import { + dateTimeToDate, + getTokenInfo, + getHexChainId, + unixToDateTime, +} from "../utils"; +import { VerticalDotsIcon } from "../icons/VerticalDots"; +import { RightArrowIcon, LeftArrowIcon } from "../icons/ArrowIcons"; +import { Styles } from "../pages/invoices/InvoicesStyles"; +// import { GenerateInvoicePDFMenuItem } from "./GenerateInvoicePDF"; +import { FilterIcon } from "../icons/FilterIcon"; +import { InvoiceResult } from "@/graphql/subgraph"; +import { Chain, ChainId } from "@/utils"; + +type InvoiceComponentProps = { + invoice: InvoiceResult; +}; + +type InvoiceStatusLabelProps = InvoiceComponentProps & { + onClick?: () => void; + cursor?: string; +}; + +const InvoiceStatusLabel: React.FC = ({ + invoice, + ...props +}) => { + const { funded, label, loading } = useInvoiceStatus(invoice); + const { isLocked, terminationTime } = invoice; + const terminated = terminationTime.gt(Date.now()); + const disputeResolved = label === "Dispute Resolved"; + return ( + + + {loading ? : label} + + + ); +}; + +type InvoiceBadgeProps = InvoiceComponentProps; + +const InvoiceBadge: React.FC = ({ invoice, ...props }) => { + // const { invoiceType } = invoice; //TODO: source this from the subgraph + const invoiceType = "unknown"; + const schemes = { + escrow: { + bg: "rgba(128, 63, 248, 0.3)", + color: "rgba(128, 63, 248, 1)", + }, + instant: { + bg: "rgba(248, 174, 63, 0.3)", + color: "rgba(248, 174, 63, 1)", + }, + unknown: { + bg: "rgba(150,150,150,0.3)", + color: "rgba(150,150,150,1)", + }, + }; + + return ( + + {invoiceType ? invoiceType.toUpperCase() : "UNKNOWN"} + + ); +}; + +export type Router = { + push: (path: string) => void; +}; + +export type InvoiceDashboardTableProps = { + result: InvoiceResult[]; + tokenData: any; + chainId?: number; + router: Router; +}; + +type Details = { + createdAt: string; + projectName: React.ReactElement; + amount: string; + currency: React.ReactElement; + status: React.ReactElement; + action: React.ReactElement; +}; + +export const InvoiceDashboardTable: React.FC = ({ + result, + tokenData, + chainId, + router, +}) => { + const data = useMemo(() => { + if (!chainId || !result || !tokenData) return []; + const dataArray = [] as Details[]; + result.forEach((invoice, index) => { + const { decimals, symbol, image } = getTokenInfo( + chainId as ChainId, + invoice.token, + tokenData + ); + const viewInvoice = () => + router.push( + `/invoice/${getHexChainId(invoice.network as Chain)}/${ + invoice.address + }/` + //${invoice.invoiceType !== "escrow" ? invoice.invoiceType : ""}` + ); + const details = { + createdAt: dateTimeToDate(unixToDateTime(invoice.createdAt.num)), + projectName: ( + + + {invoice.projectName} + + + + ), + amount: formatUnits(invoice.total.num, decimals), + currency: ( + + + {symbol} + + ), + status: ( + + ), + action: ( + + + + + + + Manage + + {/* */} + + + ), + }; + dataArray.push(details); + }); + return dataArray; + }, [chainId, result, tokenData, router]); + + const columns = useMemo( + () => [ + { + Header: "Date Created", + accessor: "createdAt", + }, + { + Header: "Invoice Name/ID", + accessor: "projectName", + }, + { + Header: "Amount", + accessor: "amount", + isnumeric: "true", + }, + { + Header: "Currency", + accessor: "currency", + isnumeric: "true", + }, + { + Header: "Status", + accessor: "status", + }, + // { + // Header: "Action", + // accessor: "action", + // }, + ], + [] + ); + + const { + getTableProps, + getTableBodyProps, + headerGroups, + prepareRow, + // @ts-ignore + page, + // @ts-ignore + canPreviousPage, + // @ts-ignore + canNextPage, + // @ts-ignore + pageOptions, + // @ts-ignore + pageCount, + // @ts-ignore + gotoPage, + // @ts-ignore + nextPage, + // @ts-ignore + previousPage, + state: { + // @ts-ignore + pageIndex, + // @ts-ignore + pageSize, + }, + } = useTable( + { + // @ts-ignore + columns, + data, + // initialState: { pageIndex: 0 }, + }, + useSortBy, + usePagination + ); + + // cell props and getCellProps for individual cell control styling + return ( + + + + My Invoices + + + +
+ + + {headerGroups.map((headerGroup, hg) => ( + // eslint-disable-next-line react/jsx-key + + {headerGroup.headers.map((column, i) => ( + // eslint-disable-next-line react/jsx-key + + ))} + + ))} + + + { + // @ts-ignore + page.map((row, i) => { + prepareRow(row); + return ( + // eslint-disable-next-line react/jsx-key + + { + // @ts-ignore + row.cells.map((cell, index) => { + return ( + // eslint-disable-next-line react/jsx-key + + ); + }) + } + + ); + }) + } + +
+ + {column.render("Header")} + {i !== headerGroup.headers.length - 1 && ( + + + + )} + +
+ {cell.render("Cell")} +
+
+
+ } + onClick={() => previousPage()} + disabled={!canPreviousPage} + /> + + Page {pageIndex + 1} of {pageCount} + + } + onClick={() => nextPage()} + disabled={!canNextPage} + /> +
+
+ ); +}; diff --git a/mist-invoice-dapp/src/components/Loader.test.tsx b/mist-invoice-dapp/src/components/Loader.test.tsx new file mode 100644 index 0000000..5383ce4 --- /dev/null +++ b/mist-invoice-dapp/src/components/Loader.test.tsx @@ -0,0 +1,11 @@ +import { render } from "@testing-library/react"; +import React from "react"; +import { Loader } from "./Loader"; + +describe("Loader", () => { + it("should render", () => { + const view = render(); + + expect(view.asFragment()).toMatchSnapshot(); + }); +}); diff --git a/mist-invoice-dapp/src/components/Loader.tsx b/mist-invoice-dapp/src/components/Loader.tsx new file mode 100644 index 0000000..d8ad175 --- /dev/null +++ b/mist-invoice-dapp/src/components/Loader.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +export const Loader = ({ size = "38" }) => { + return ( + + + + + + + + + + + ); +}; diff --git a/mist-invoice-dapp/src/components/NavButton.test.tsx b/mist-invoice-dapp/src/components/NavButton.test.tsx new file mode 100644 index 0000000..7158e78 --- /dev/null +++ b/mist-invoice-dapp/src/components/NavButton.test.tsx @@ -0,0 +1,13 @@ +import { render } from "@testing-library/react"; +import React from "react"; +import { NavButton } from "./NavButton"; + +describe("NavButton", () => { + const mockOnClickHandler = jest.fn(); + + it("should render", () => { + const view = render(); + + expect(view.asFragment()).toMatchSnapshot(); + }); +}); diff --git a/mist-invoice-dapp/src/components/NavButton.tsx b/mist-invoice-dapp/src/components/NavButton.tsx new file mode 100644 index 0000000..462e2f0 --- /dev/null +++ b/mist-invoice-dapp/src/components/NavButton.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +import { StyledButton } from "./StyledButton"; + +export type NavButtonProps = { + onClick: () => void; +}; + +export const NavButton: React.FC> = ({ + onClick, + children, +}) => ( + + {children} + +); diff --git a/mist-invoice-dapp/src/components/NetworkChangeAlertModal.tsx b/mist-invoice-dapp/src/components/NetworkChangeAlertModal.tsx new file mode 100644 index 0000000..c038248 --- /dev/null +++ b/mist-invoice-dapp/src/components/NetworkChangeAlertModal.tsx @@ -0,0 +1,54 @@ +import { + Modal, + ModalCloseButton, + ModalContent, + ModalOverlay, + ModalHeader, + ModalBody, +} from "@chakra-ui/react"; +import React from "react"; +import { getNetworkName } from "../utils"; + +export type NetworkChangeAlertModalProps = { + showChainChangeAlert: boolean; + setShowChainChangeAlert: (show: boolean) => void; + chainId: number; +}; + +export const NetworkChangeAlertModal: React.FC< + NetworkChangeAlertModalProps +> = ({ showChainChangeAlert, setShowChainChangeAlert, chainId }) => ( + setShowChainChangeAlert(false)} + > + + + + Attention + + +
+ You are changing the network to {getNetworkName(chainId)}. +
+
+
+ You must complete all invoice creation steps on the same chain. +
+ If you have not yet input any information, you can continue. +
+ Otherwise, please return to Step 1 and complete all steps on the same + network. +
+
+ +
+
+); diff --git a/mist-invoice-dapp/src/components/OrderedInput.tsx b/mist-invoice-dapp/src/components/OrderedInput.tsx new file mode 100644 index 0000000..75989eb --- /dev/null +++ b/mist-invoice-dapp/src/components/OrderedInput.tsx @@ -0,0 +1,366 @@ +import { + Flex, + Input, + InputGroup, + InputLeftElement, + Select, + Text, + Textarea, + Tooltip, + VStack, +} from "@chakra-ui/react"; +import React, { useState } from "react"; + +import { QuestionIcon } from "../icons/QuestionIcon"; +import { isValidLink } from "../utils"; + +export type OrderedLinkInputProps = { + label: string; + linkType: string; + setLinkType: (linkType: string) => void; + value: string; + setValue: (value: string) => void; + infoText?: string; + tooltip?: string; + placeholder?: string; + type?: string; + required?: string; +} & React.ComponentProps; + +export const OrderedLinkInput: React.FC = ({ + label, + linkType, + setLinkType, + value, + setValue, + infoText, + tooltip, + placeholder, + type = "text", + required, + ...props +}) => { + const [protocol, setProtocol] = useState(`${linkType}://`); + const [input, setInput] = useState(""); + const [isInvalid, setInvalid] = useState(false); + + return ( + + + + {label} + + {infoText && {infoText}} + {tooltip && ( + + + + )} + + + + {required} + + + + + + + + { + let newInput = e.target.value; + let newProtocol = protocol; + if (newInput.startsWith("https://") && newInput.length > 8) { + newProtocol = "https://"; + newInput = newInput.slice(8); + } else if ( + newInput.startsWith("ipfs://") && + newInput.length > 7 + ) { + newProtocol = "ipfs://"; + newInput = newInput.slice(7); + } + const newValue = newProtocol + newInput; + const isValid = isValidLink(newValue); + setValue(newValue); + setLinkType(newProtocol.substring(0, newProtocol.length - 3)); + setInvalid(!isValid); + setInput(newInput); + setProtocol(newProtocol); + }} + placeholder={placeholder} + color="black" + border="1px" + borderColor="lightgrey" + _hover={{ borderColor: "lightgrey" }} + isInvalid={isInvalid} + _invalid={{ border: "1px solid", borderColor: "red" }} + /> + + {isInvalid && ( + + Invalid URL + + )} + + + ); +}; + +export type OrderedInputProps = { + label: string; + value: string; + setValue: (value: string) => void; + infoText?: string; + tooltip?: string; + placeholder?: string; + type?: string; + required?: string; + isInvalid?: boolean; + isDisabled?: boolean; + error?: string; +} & React.ComponentProps; + +export const OrderedInput: React.FC = ({ + label, + value, + setValue, + infoText, + tooltip, + placeholder, + required, + isInvalid = false, + isDisabled = false, + type = "text", + error = "", + ...props +}) => { + return ( + + + + {label} + + {infoText && ( + + {infoText} + + )} + {tooltip && ( + + + + )} + + + + {required} + + + + setValue(e.target.value)} + placeholder={placeholder} + color="black" + border="1px" + borderColor="lightgrey" + _hover={{ borderColor: "lightgrey" }} + isDisabled={isDisabled} + isInvalid={isInvalid} + _invalid={{ border: "1px solid", borderColor: "red" }} + /> + {error && ( + + {error} + + )} + + + ); +}; + +export type OrderedSelectProps = { + label: string; + value: string; + setValue: (value: string) => void; + infoText?: string; + tooltip?: string; + required?: string; + isDisabled?: boolean; +}; + +export const OrderedSelect: React.FC< + React.PropsWithChildren +> = ({ + label, + value, + setValue, + infoText, + tooltip, + required, + isDisabled = false, + children, +}) => { + return ( + + + + {label} + + {infoText && ( + + {infoText} + + )} + {tooltip && ( + + + + )} + + + + {required} + + + + + ); +}; + +export type OrderedTextareaProps = { + label: string; + value: string; + setValue: (value: string) => void; + infoText?: string; + tooltip?: string; + placeholder?: string; + maxLength?: number; + required?: string; + isDisabled?: boolean; + type?: string; +}; + +export const OrderedTextarea: React.FC = ({ + label, + value, + setValue, + infoText, + tooltip, + placeholder, + maxLength, + required, + isDisabled = false, + type = "text", +}) => { + return ( + + + + + {label} + + {tooltip && ( + + + + )} + + + {infoText && ( + + {infoText}{" "} + {required && ( + • {required} + )} + + )} + {required && !infoText && ( + + {required} + + )} + + +