From 51877a865028174b3ae3eb9c09039ea821c6403a Mon Sep 17 00:00:00 2001 From: kevin-devstack Date: Sat, 5 Oct 2024 15:31:42 +0530 Subject: [PATCH] feat(app): translation package migration (#504) --- .github/workflows/beta-build-images.yaml | 39 + apps/app/i18n.js | 43 - apps/app/next-env.d.ts | 1 + apps/app/next.config.js | 7 +- apps/app/package.json | 2 + .../src/app/[locale]/blocks/[hash]/layout.tsx | 53 ++ .../app/[locale]/blocks/[hash]/loading.tsx | 12 + .../src/app/[locale]/blocks/[hash]/page.tsx | 60 ++ apps/app/src/app/[locale]/layout.tsx | 91 ++ apps/app/src/app/_not-found-component.tsx | 11 + apps/app/src/app/global-error.tsx | 50 ++ apps/app/src/app/icon.ico | Bin 0 -> 15406 bytes apps/app/src/app/layout.tsx | 70 ++ apps/app/src/app/not-found.ts | 1 + apps/app/src/components/ActiveLink.tsx | 14 +- .../src/components/Address/AccessKeyRow.tsx | 6 +- .../app/src/components/Address/AccessKeys.tsx | 11 +- apps/app/src/components/Address/Balance.tsx | 20 +- .../Address/Contract/ContractCode.tsx | 2 +- .../src/components/Address/Contract/Info.tsx | 3 +- .../Address/Contract/VerificationStatus.tsx | 2 +- .../Address/Contract/ViewOrChange.tsx | 2 +- .../Address/Contract/ViewOrChangeAbi.tsx | 2 +- .../components/Address/NFTTransactions.tsx | 80 +- apps/app/src/components/Address/Receipts.tsx | 112 ++- .../components/Address/TokenTransactions.tsx | 81 +- .../src/components/Address/Transactions.tsx | 104 ++- apps/app/src/components/Blocks/Detail.tsx | 40 +- apps/app/src/components/Blocks/Latest.tsx | 23 +- apps/app/src/components/Blocks/List.tsx | 26 +- apps/app/src/components/Charts/Chart.tsx | 26 +- apps/app/src/components/Charts/TpsChart.tsx | 26 +- apps/app/src/components/Error.tsx | 14 +- apps/app/src/components/Layouts/Footer.tsx | 6 +- .../src/components/Layouts/FormContact.tsx | 4 +- apps/app/src/components/Layouts/Header.tsx | 91 +- .../components/NodeExplorer/Delegators.tsx | 2 +- apps/app/src/components/Tokens/FT/FAQ.tsx | 2 +- apps/app/src/components/Tokens/FT/Holders.tsx | 2 +- .../app/src/components/Tokens/FT/Overview.tsx | 2 +- .../src/components/Tokens/FT/TokenFilter.tsx | 2 +- .../src/components/Tokens/FT/Transfers.tsx | 25 +- apps/app/src/components/Tokens/FTList.tsx | 40 +- .../app/src/components/Tokens/FTTransfers.tsx | 14 +- apps/app/src/components/Tokens/NFT/Detail.tsx | 2 +- .../app/src/components/Tokens/NFT/Holders.tsx | 2 +- .../src/components/Tokens/NFT/Inventory.tsx | 2 +- .../components/Tokens/NFT/TokenTransfers.tsx | 6 +- .../src/components/Tokens/NFT/Transfers.tsx | 8 +- apps/app/src/components/Tokens/NFTList.tsx | 32 +- .../src/components/Tokens/NFTTransfers.tsx | 18 +- .../components/Transactions/Action/AddKey.tsx | 34 +- .../Transactions/Action/Burrow/Borrow.tsx | 2 +- .../Action/Burrow/DecreaseCollateral.tsx | 2 +- .../Transactions/Action/Burrow/Deposit.tsx | 2 +- .../Action/Burrow/DopositToReserve.tsx | 2 +- .../Action/Burrow/IncreaseCollateral.tsx | 2 +- .../Transactions/Action/Burrow/Repay.tsx | 2 +- .../Action/Burrow/WithdrawSucceeded.tsx | 2 +- .../Transactions/Action/CreateAccount.tsx | 2 +- .../Transactions/Action/DeleteAccount.tsx | 2 +- .../Transactions/Action/DeployContract.tsx | 2 +- .../Transactions/Action/FunctionCall.tsx | 2 +- .../Transactions/Action/Ref/Swap.tsx | 2 +- .../Transactions/Action/Transfer.tsx | 2 +- .../src/components/Transactions/Details.tsx | 56 +- .../src/components/Transactions/Latest.tsx | 16 +- apps/app/src/components/Transactions/List.tsx | 101 ++- .../src/components/Transactions/Overview.tsx | 28 +- .../Transactions/ReceiptSummary.tsx | 8 +- .../Transactions/Receipts/Action/AddKey.tsx | 34 +- .../Receipts/Action/CreateAccount.tsx | 10 +- .../Receipts/Action/DeleteAccount.tsx | 12 +- .../Receipts/Action/DeleteKey.tsx | 8 +- .../Receipts/Action/DeployContract.tsx | 10 +- .../Receipts/Action/FunctionCall.tsx | 10 +- .../Transactions/Receipts/Action/Stake.tsx | 8 +- .../Transactions/Receipts/Action/Transfer.tsx | 10 +- .../Transactions/Receipts/ReceiptInfo.tsx | 10 +- .../Transactions/Receipts/ReceiptKind.tsx | 6 +- .../Transactions/Receipts/ReceiptRow.tsx | 40 +- .../Receipts/ReceiptSummaryRow.tsx | 2 +- .../TreeReceipts/Action/AddKey.tsx | 30 +- .../TreeReceipts/Action/CreateAccount.tsx | 10 +- .../TreeReceipts/Action/DeleteAccount.tsx | 10 +- .../TreeReceipts/Action/DeleteKey.tsx | 8 +- .../TreeReceipts/Action/DeployContract.tsx | 10 +- .../TreeReceipts/Action/FunctionCall.tsx | 10 +- .../TreeReceipts/Action/Stake.tsx | 9 +- .../TreeReceipts/Action/Transfer.tsx | 10 +- .../TreeReceipts/TreeReceiptDetails.tsx | 2 +- apps/app/src/components/app/ActiveLink.tsx | 48 + .../app/src/components/app/Blocks/Details.tsx | 259 ++++++ apps/app/src/components/app/Blocks/List.tsx | 296 +++++++ apps/app/src/components/app/Collapse.tsx | 35 + apps/app/src/components/app/Error.tsx | 23 + apps/app/src/components/app/Icons/Arrow.tsx | 21 + .../src/components/app/Icons/ArrowDown.tsx | 18 + apps/app/src/components/app/Icons/ArrowUp.tsx | 19 + apps/app/src/components/app/Icons/Button.tsx | 101 +++ apps/app/src/components/app/Icons/Check.tsx | 14 + apps/app/src/components/app/Icons/Clock.tsx | 26 + .../src/components/app/Icons/CloseCircle.tsx | 26 + .../app/src/components/app/Icons/CopyIcon.tsx | 24 + .../app/src/components/app/Icons/Download.tsx | 20 + .../components/app/Icons/FaCheckCircle.tsx | 13 + .../components/app/Icons/FaChevronLeft.tsx | 19 + .../components/app/Icons/FaChevronRight.tsx | 19 + .../app/Icons/FaExternalLinkAlt.tsx | 9 + .../components/app/Icons/FaHourglassStart.tsx | 20 + apps/app/src/components/app/Icons/FaInbox.tsx | 16 + .../components/app/Icons/FaTimesCircle.tsx | 12 + .../src/components/app/Icons/FileSlash.tsx | 18 + apps/app/src/components/app/Icons/Filter.tsx | 19 + apps/app/src/components/app/Icons/Menu.tsx | 21 + .../src/components/app/Icons/QRCodeIcon.tsx | 25 + .../app/src/components/app/Icons/Question.tsx | 25 + apps/app/src/components/app/Icons/Rpc.tsx | 14 + .../src/components/app/Icons/SearchIcon.tsx | 24 + .../app/src/components/app/Icons/SortIcon.tsx | 16 + apps/app/src/components/app/Icons/Status.tsx | 55 ++ apps/app/src/components/app/Icons/User.tsx | 20 + .../src/components/app/Icons/WarningIcon.tsx | 23 + .../app/src/components/app/Layouts/Footer.tsx | 210 +++++ .../app/src/components/app/Layouts/Header.tsx | 754 ++++++++++++++++ apps/app/src/components/app/Layouts/Menu.tsx | 118 +++ .../src/components/app/Layouts/RpcMenu.tsx | 25 + apps/app/src/components/app/Layouts/index.tsx | 44 + apps/app/src/components/app/SponserdText.tsx | 65 ++ apps/app/src/components/app/SwitchButton.tsx | 22 + .../components/app/common/CursorPaginator.tsx | 87 ++ .../components/app/common/ErrorMessage.tsx | 23 + .../app/src/components/app/common/Filters.tsx | 38 + .../src/components/app/common/Paginator.tsx | 130 +++ apps/app/src/components/app/common/QrCode.tsx | 64 ++ apps/app/src/components/app/common/Search.tsx | 256 ++++++ .../app/src/components/app/common/Spinner.tsx | 7 + apps/app/src/components/app/common/Status.tsx | 55 ++ apps/app/src/components/app/common/Table.tsx | 196 ++++ .../src/components/app/common/TimeStamp.tsx | 27 + .../components/app/common/TokenHoldings.tsx | 208 +++++ .../src/components/app/common/TokenImage.tsx | 79 ++ .../app/skeleton/address/accessKeyTab.tsx | 46 + .../app/skeleton/address/balance.tsx | 93 ++ .../app/skeleton/address/contractTab.tsx | 29 + .../app/skeleton/address/dynamicTab.tsx | 30 + .../app/skeleton/address/nftTokenTxns.tsx | 13 + .../app/skeleton/address/overview.tsx | 105 +++ .../components/app/skeleton/address/tab.tsx | 101 +++ .../app/skeleton/address/tokenTransaction.tsx | 13 + .../app/skeleton/address/transaction.tsx | 13 + .../components/app/skeleton/blocks/hash.tsx | 117 +++ .../components/app/skeleton/blocks/list.tsx | 32 + .../app/skeleton/common/Skeleton.tsx | 13 + .../components/app/skeleton/common/table.tsx | 32 + .../src/components/common/CursorPaginator.tsx | 42 +- apps/app/src/components/common/Paginator.tsx | 65 +- apps/app/src/components/common/Search.tsx | 71 +- apps/app/src/components/common/Spinner.tsx | 7 +- .../src/components/common/TokenHoldings.tsx | 2 +- apps/app/src/components/common/TokenInfo.tsx | 2 +- .../src/components/skeleton/charts/Detail.tsx | 6 +- .../src/components/skeleton/charts/Index.tsx | 4 +- .../src/components/skeleton/common/Detail.tsx | 14 +- .../src/components/skeleton/ft/Overview.tsx | 4 +- .../src/components/skeleton/home/Overview.tsx | 4 +- .../src/components/skeleton/txns/Summary.tsx | 8 +- apps/app/src/i18n/request.ts | 57 ++ apps/app/src/i18n/routing.ts | 32 + apps/app/src/middleware.ts | 49 + apps/app/src/pages/404.tsx | 16 + apps/app/src/pages/[locale]/about.tsx | 114 +++ apps/app/src/pages/[locale]/address/[id].tsx | 806 +++++++++++++++++ apps/app/src/pages/[locale]/advertise.tsx | 386 ++++++++ apps/app/src/pages/[locale]/apis.tsx | 625 +++++++++++++ apps/app/src/pages/[locale]/blocks/index.tsx | 151 ++++ .../pages/[locale]/charts/active-accounts.tsx | 105 +++ .../src/pages/[locale]/charts/addresses.tsx | 146 +++ apps/app/src/pages/[locale]/charts/blocks.tsx | 145 +++ apps/app/src/pages/[locale]/charts/index.tsx | 122 +++ .../src/pages/[locale]/charts/market-cap.tsx | 147 +++ .../src/pages/[locale]/charts/near-price.tsx | 149 ++++ .../src/pages/[locale]/charts/near-supply.tsx | 153 ++++ apps/app/src/pages/[locale]/charts/tps.tsx | 159 ++++ .../app/src/pages/[locale]/charts/txn-fee.tsx | 146 +++ .../src/pages/[locale]/charts/txn-volume.tsx | 148 ++++ apps/app/src/pages/[locale]/charts/txns.tsx | 142 +++ apps/app/src/pages/[locale]/contact.tsx | 523 +++++++++++ apps/app/src/pages/[locale]/exportdata.tsx | 117 +++ .../app/src/pages/[locale]/hash/[receipt].tsx | 56 ++ apps/app/src/pages/[locale]/index.tsx | 222 +++++ .../[locale]/nft-token/[id]/[tid]/index.tsx | 165 ++++ .../pages/[locale]/nft-token/[id]/index.tsx | 380 ++++++++ .../pages/[locale]/nft-token/exportdata.tsx | 114 +++ apps/app/src/pages/[locale]/nft-tokens.tsx | 181 ++++ apps/app/src/pages/[locale]/nft-tokentxns.tsx | 171 ++++ .../src/pages/[locale]/node-explorer/[id].tsx | 136 +++ .../pages/[locale]/node-explorer/index.tsx | 135 +++ .../pages/[locale]/terms-and-conditions.tsx | 488 ++++++++++ apps/app/src/pages/[locale]/token/[id].tsx | 436 +++++++++ .../src/pages/[locale]/token/exportdata.tsx | 113 +++ apps/app/src/pages/[locale]/tokens.tsx | 180 ++++ apps/app/src/pages/[locale]/tokentxns.tsx | 176 ++++ apps/app/src/pages/[locale]/txns/[hash].tsx | 496 +++++++++++ apps/app/src/pages/[locale]/txns/index.tsx | 158 ++++ .../pages/[locale]/verify-contract/index.tsx | 130 +++ apps/app/src/pages/_app.tsx | 20 +- apps/app/src/pages/_document.tsx | 2 +- apps/app/src/pages/{_error.jsx => _error.tsx} | 4 +- apps/app/src/pages/about.tsx | 29 +- apps/app/src/pages/address/[id].tsx | 62 +- apps/app/src/pages/advertise.tsx | 31 +- apps/app/src/pages/apis.tsx | 17 +- apps/app/src/pages/blocks/[hash].tsx | 166 ---- apps/app/src/pages/blocks/index.tsx | 40 +- apps/app/src/pages/charts/active-accounts.tsx | 22 +- apps/app/src/pages/charts/addresses.tsx | 42 +- apps/app/src/pages/charts/blocks.tsx | 42 +- apps/app/src/pages/charts/index.tsx | 42 +- apps/app/src/pages/charts/market-cap.tsx | 44 +- apps/app/src/pages/charts/near-price.tsx | 45 +- apps/app/src/pages/charts/near-supply.tsx | 47 +- apps/app/src/pages/charts/tps.tsx | 17 +- apps/app/src/pages/charts/txn-fee.tsx | 42 +- apps/app/src/pages/charts/txn-volume.tsx | 45 +- apps/app/src/pages/charts/txns.tsx | 42 +- apps/app/src/pages/contact.tsx | 27 +- apps/app/src/pages/exportdata.tsx | 18 +- apps/app/src/pages/index.tsx | 42 +- .../src/pages/nft-token/[id]/[tid]/index.tsx | 14 + apps/app/src/pages/nft-token/[id]/index.tsx | 28 +- apps/app/src/pages/nft-token/exportdata.tsx | 15 + apps/app/src/pages/nft-tokens.tsx | 15 + apps/app/src/pages/nft-tokentxns.tsx | 42 +- apps/app/src/pages/node-explorer/[id].tsx | 47 +- apps/app/src/pages/node-explorer/index.tsx | 32 +- apps/app/src/pages/terms-and-conditions.tsx | 31 +- apps/app/src/pages/token/[id].tsx | 35 +- apps/app/src/pages/token/exportdata.tsx | 16 + apps/app/src/pages/tokens.tsx | 16 + apps/app/src/pages/tokentxns.tsx | 41 +- apps/app/src/pages/txns/[hash].tsx | 37 +- apps/app/src/pages/txns/index.tsx | 38 +- apps/app/src/pages/verify-contract/index.tsx | 12 + apps/app/src/styles/globals.css | 10 + apps/app/src/utils/app/api.ts | 31 + apps/app/src/utils/app/config.ts | 61 ++ apps/app/src/utils/app/libs.ts | 495 +++++++++++ apps/app/src/utils/app/near.ts | 835 ++++++++++++++++++ apps/app/src/utils/near.ts | 4 +- apps/app/src/utils/types.ts | 1 + apps/app/tsconfig.json | 3 +- yarn.lock | 103 ++- 253 files changed, 16099 insertions(+), 1320 deletions(-) create mode 100644 .github/workflows/beta-build-images.yaml delete mode 100644 apps/app/i18n.js create mode 100644 apps/app/src/app/[locale]/blocks/[hash]/layout.tsx create mode 100644 apps/app/src/app/[locale]/blocks/[hash]/loading.tsx create mode 100644 apps/app/src/app/[locale]/blocks/[hash]/page.tsx create mode 100644 apps/app/src/app/[locale]/layout.tsx create mode 100644 apps/app/src/app/_not-found-component.tsx create mode 100644 apps/app/src/app/global-error.tsx create mode 100644 apps/app/src/app/icon.ico create mode 100644 apps/app/src/app/layout.tsx create mode 100644 apps/app/src/app/not-found.ts create mode 100644 apps/app/src/components/app/ActiveLink.tsx create mode 100644 apps/app/src/components/app/Blocks/Details.tsx create mode 100644 apps/app/src/components/app/Blocks/List.tsx create mode 100644 apps/app/src/components/app/Collapse.tsx create mode 100644 apps/app/src/components/app/Error.tsx create mode 100644 apps/app/src/components/app/Icons/Arrow.tsx create mode 100644 apps/app/src/components/app/Icons/ArrowDown.tsx create mode 100644 apps/app/src/components/app/Icons/ArrowUp.tsx create mode 100644 apps/app/src/components/app/Icons/Button.tsx create mode 100644 apps/app/src/components/app/Icons/Check.tsx create mode 100644 apps/app/src/components/app/Icons/Clock.tsx create mode 100644 apps/app/src/components/app/Icons/CloseCircle.tsx create mode 100644 apps/app/src/components/app/Icons/CopyIcon.tsx create mode 100644 apps/app/src/components/app/Icons/Download.tsx create mode 100644 apps/app/src/components/app/Icons/FaCheckCircle.tsx create mode 100644 apps/app/src/components/app/Icons/FaChevronLeft.tsx create mode 100644 apps/app/src/components/app/Icons/FaChevronRight.tsx create mode 100644 apps/app/src/components/app/Icons/FaExternalLinkAlt.tsx create mode 100644 apps/app/src/components/app/Icons/FaHourglassStart.tsx create mode 100644 apps/app/src/components/app/Icons/FaInbox.tsx create mode 100644 apps/app/src/components/app/Icons/FaTimesCircle.tsx create mode 100644 apps/app/src/components/app/Icons/FileSlash.tsx create mode 100644 apps/app/src/components/app/Icons/Filter.tsx create mode 100644 apps/app/src/components/app/Icons/Menu.tsx create mode 100644 apps/app/src/components/app/Icons/QRCodeIcon.tsx create mode 100644 apps/app/src/components/app/Icons/Question.tsx create mode 100644 apps/app/src/components/app/Icons/Rpc.tsx create mode 100644 apps/app/src/components/app/Icons/SearchIcon.tsx create mode 100644 apps/app/src/components/app/Icons/SortIcon.tsx create mode 100644 apps/app/src/components/app/Icons/Status.tsx create mode 100644 apps/app/src/components/app/Icons/User.tsx create mode 100644 apps/app/src/components/app/Icons/WarningIcon.tsx create mode 100644 apps/app/src/components/app/Layouts/Footer.tsx create mode 100644 apps/app/src/components/app/Layouts/Header.tsx create mode 100644 apps/app/src/components/app/Layouts/Menu.tsx create mode 100644 apps/app/src/components/app/Layouts/RpcMenu.tsx create mode 100644 apps/app/src/components/app/Layouts/index.tsx create mode 100644 apps/app/src/components/app/SponserdText.tsx create mode 100644 apps/app/src/components/app/SwitchButton.tsx create mode 100644 apps/app/src/components/app/common/CursorPaginator.tsx create mode 100644 apps/app/src/components/app/common/ErrorMessage.tsx create mode 100644 apps/app/src/components/app/common/Filters.tsx create mode 100644 apps/app/src/components/app/common/Paginator.tsx create mode 100644 apps/app/src/components/app/common/QrCode.tsx create mode 100644 apps/app/src/components/app/common/Search.tsx create mode 100644 apps/app/src/components/app/common/Spinner.tsx create mode 100644 apps/app/src/components/app/common/Status.tsx create mode 100644 apps/app/src/components/app/common/Table.tsx create mode 100644 apps/app/src/components/app/common/TimeStamp.tsx create mode 100644 apps/app/src/components/app/common/TokenHoldings.tsx create mode 100644 apps/app/src/components/app/common/TokenImage.tsx create mode 100644 apps/app/src/components/app/skeleton/address/accessKeyTab.tsx create mode 100644 apps/app/src/components/app/skeleton/address/balance.tsx create mode 100644 apps/app/src/components/app/skeleton/address/contractTab.tsx create mode 100644 apps/app/src/components/app/skeleton/address/dynamicTab.tsx create mode 100644 apps/app/src/components/app/skeleton/address/nftTokenTxns.tsx create mode 100644 apps/app/src/components/app/skeleton/address/overview.tsx create mode 100644 apps/app/src/components/app/skeleton/address/tab.tsx create mode 100644 apps/app/src/components/app/skeleton/address/tokenTransaction.tsx create mode 100644 apps/app/src/components/app/skeleton/address/transaction.tsx create mode 100644 apps/app/src/components/app/skeleton/blocks/hash.tsx create mode 100644 apps/app/src/components/app/skeleton/blocks/list.tsx create mode 100644 apps/app/src/components/app/skeleton/common/Skeleton.tsx create mode 100644 apps/app/src/components/app/skeleton/common/table.tsx create mode 100644 apps/app/src/i18n/request.ts create mode 100644 apps/app/src/i18n/routing.ts create mode 100644 apps/app/src/middleware.ts create mode 100644 apps/app/src/pages/[locale]/about.tsx create mode 100644 apps/app/src/pages/[locale]/address/[id].tsx create mode 100644 apps/app/src/pages/[locale]/advertise.tsx create mode 100644 apps/app/src/pages/[locale]/apis.tsx create mode 100644 apps/app/src/pages/[locale]/blocks/index.tsx create mode 100644 apps/app/src/pages/[locale]/charts/active-accounts.tsx create mode 100644 apps/app/src/pages/[locale]/charts/addresses.tsx create mode 100644 apps/app/src/pages/[locale]/charts/blocks.tsx create mode 100644 apps/app/src/pages/[locale]/charts/index.tsx create mode 100644 apps/app/src/pages/[locale]/charts/market-cap.tsx create mode 100644 apps/app/src/pages/[locale]/charts/near-price.tsx create mode 100644 apps/app/src/pages/[locale]/charts/near-supply.tsx create mode 100644 apps/app/src/pages/[locale]/charts/tps.tsx create mode 100644 apps/app/src/pages/[locale]/charts/txn-fee.tsx create mode 100644 apps/app/src/pages/[locale]/charts/txn-volume.tsx create mode 100644 apps/app/src/pages/[locale]/charts/txns.tsx create mode 100644 apps/app/src/pages/[locale]/contact.tsx create mode 100644 apps/app/src/pages/[locale]/exportdata.tsx create mode 100644 apps/app/src/pages/[locale]/hash/[receipt].tsx create mode 100644 apps/app/src/pages/[locale]/index.tsx create mode 100644 apps/app/src/pages/[locale]/nft-token/[id]/[tid]/index.tsx create mode 100644 apps/app/src/pages/[locale]/nft-token/[id]/index.tsx create mode 100644 apps/app/src/pages/[locale]/nft-token/exportdata.tsx create mode 100644 apps/app/src/pages/[locale]/nft-tokens.tsx create mode 100644 apps/app/src/pages/[locale]/nft-tokentxns.tsx create mode 100644 apps/app/src/pages/[locale]/node-explorer/[id].tsx create mode 100644 apps/app/src/pages/[locale]/node-explorer/index.tsx create mode 100644 apps/app/src/pages/[locale]/terms-and-conditions.tsx create mode 100644 apps/app/src/pages/[locale]/token/[id].tsx create mode 100644 apps/app/src/pages/[locale]/token/exportdata.tsx create mode 100644 apps/app/src/pages/[locale]/tokens.tsx create mode 100644 apps/app/src/pages/[locale]/tokentxns.tsx create mode 100644 apps/app/src/pages/[locale]/txns/[hash].tsx create mode 100644 apps/app/src/pages/[locale]/txns/index.tsx create mode 100644 apps/app/src/pages/[locale]/verify-contract/index.tsx rename apps/app/src/pages/{_error.jsx => _error.tsx} (80%) delete mode 100644 apps/app/src/pages/blocks/[hash].tsx create mode 100644 apps/app/src/utils/app/api.ts create mode 100644 apps/app/src/utils/app/config.ts create mode 100644 apps/app/src/utils/app/libs.ts create mode 100644 apps/app/src/utils/app/near.ts diff --git a/.github/workflows/beta-build-images.yaml b/.github/workflows/beta-build-images.yaml new file mode 100644 index 00000000..9d621783 --- /dev/null +++ b/.github/workflows/beta-build-images.yaml @@ -0,0 +1,39 @@ +name: Build Docker Images + +on: + push: + branches: ['beta'] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/amd64,linux/arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker Login + uses: docker/login-action@v3.0.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push (APP) + uses: docker/build-push-action@v5 + with: + context: . + file: apps/app/Dockerfile + platforms: linux/amd64 + push: true + tags: ghcr.io/nearblocks/app:beta + cache-from: type=registry,ref=ghcr.io/nearblocks/app:beta + cache-to: type=inline diff --git a/apps/app/i18n.js b/apps/app/i18n.js deleted file mode 100644 index ffda7e07..00000000 --- a/apps/app/i18n.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - locales: [ - 'en', - 'kr', - 'id', - 'zh-cn', - 'zh-hk', - 'ua', - 'ru', - 'es', - 'vi', - 'ph', - 'fr', - 'jp', - 'th', - 'it', - ], - defaultLocale: 'en', - pages: { - '*': ['common'], - '/': ['home'], - '/404': ['404'], - 'rgx:^/address': ['address', 'txns', 'token'], - 'rgx:^/exportdata': ['home'], - 'rgx:^/blocks': ['blocks', 'txns'], - 'rgx:^/txns': ['txns'], - 'rgx:^/hash': ['txns'], - 'rgx:^/charts': ['charts'], - 'rgx:^/tokentxns': ['token', 'txns'], - 'rgx:^/token': ['token', 'txns'], - 'rgx:^/events': ['home'], - 'rgx:^/nft-tokentxns': ['token', 'txns'], - 'rgx:^/nft-tokens': ['token', 'txns'], - 'rgx:^/nft-token': ['token', 'txns'], - 'rgx:^/kb': ['kb'], - 'rgx:^/about': ['about'], - 'rgx:^/terms-and-conditions': ['terms'], - 'rgx:^/contact': ['contact'], - 'rgx:^/advertise': ['home'], - }, - loadLocaleFrom: (lang, ns) => - import(`nearblock-translations/${lang}/${ns}.json`).then((m) => m.default), -}; diff --git a/apps/app/next-env.d.ts b/apps/app/next-env.d.ts index 4f11a03d..fd36f949 100644 --- a/apps/app/next-env.d.ts +++ b/apps/app/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/apps/app/next.config.js b/apps/app/next.config.js index 64a1ba02..ce0dc21f 100644 --- a/apps/app/next.config.js +++ b/apps/app/next.config.js @@ -1,10 +1,12 @@ const path = require('path'); const { configureRuntimeEnv } = require('next-runtime-env/build/configure'); -const nextTranslate = require('next-translate-plugin'); + +const withNextIntl = require('next-intl/plugin')(); + configureRuntimeEnv(); /** @type {import('next').NextConfig} */ -const nextConfig = nextTranslate({ +const nextConfig = withNextIntl({ reactStrictMode: true, poweredByHeader: false, optimizeFonts: false, @@ -49,6 +51,7 @@ module.exports = nextConfig; const { withSentryConfig } = require('@sentry/nextjs'); +// Skip all paths that should not be internationalized module.exports = withSentryConfig(module.exports, { // For all available options, see: // https://github.com/getsentry/sentry-webpack-plugin#options diff --git a/apps/app/package.json b/apps/app/package.json index beb39742..0035824f 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -59,7 +59,9 @@ "near-api-js": "5.0.0", "near-social-vm": "github:NearSocial/VM#2.5.5", "nearblock-translations": "https://github.com/Nearblocks/translations.git#516d489658dea178226e90f1707935e970598c51", + "nearblocks-trans-next-intl": "https://github.com/kevin-devstack/translations.git#c23d13c6e049ad5721dfd71a8f0cbd8e6725c6ae", "next": "14.2.5", + "next-intl": "^3.19.4", "next-runtime-env": "1.x", "next-sitemap": "4.2.3", "next-themes": "^0.3.0", diff --git a/apps/app/src/app/[locale]/blocks/[hash]/layout.tsx b/apps/app/src/app/[locale]/blocks/[hash]/layout.tsx new file mode 100644 index 00000000..8256e4f4 --- /dev/null +++ b/apps/app/src/app/[locale]/blocks/[hash]/layout.tsx @@ -0,0 +1,53 @@ +import { appUrl } from '@/utils/app/config'; +import { getTranslations, unstable_setRequestLocale } from 'next-intl/server'; + +const network = process.env.NEXT_PUBLIC_NETWORK_ID; +const ogUrl = process.env.NEXT_PUBLIC_OG_URL; + +export async function generateMetadata({ + params, +}: { + params: { hash: string; locale: string }; +}) { + unstable_setRequestLocale(params?.locale); + + const t = await getTranslations({ locale: params.locale }); + + const thumbnail = `${ogUrl}/thumbnail/basic?title=${encodeURIComponent( + t('heading') || 'Latest Near Protocol Blocks', + )}&brand=near`; + + const metaTitle = + t('block.metaTitle', { block: params.hash }) || + 'All Near Latest Protocol Blocks | NearBlocks'; + const metaDescription = + t('block.metaDescription', { block: params.hash }) || + 'All Near (Ⓝ Blocks that are included in Near blockchain. The timestamp, author, gas used, gas price and included transactions are shown.'; + + return { + title: `${network === 'testnet' ? 'TESTNET' : ''} ${metaTitle}`, + description: metaDescription, + openGraph: { + title: metaTitle, + description: metaDescription, + images: [thumbnail], + }, + twitter: { + title: metaTitle, + description: metaDescription, + images: [thumbnail], + }, + alternates: { + canonical: `${appUrl}/blocks/${params.hash}`, + }, + }; +} + +export default async function HaseLayout({ + children, +}: { + children: React.ReactNode; + params: any; +}) { + return <>{children}; +} diff --git a/apps/app/src/app/[locale]/blocks/[hash]/loading.tsx b/apps/app/src/app/[locale]/blocks/[hash]/loading.tsx new file mode 100644 index 00000000..2473ef0e --- /dev/null +++ b/apps/app/src/app/[locale]/blocks/[hash]/loading.tsx @@ -0,0 +1,12 @@ +import HashLoading from '@/components/app/skeleton/blocks/hash'; + +export default function Loading() { + return ( + <> +
+ +
+
+ + ); +} diff --git a/apps/app/src/app/[locale]/blocks/[hash]/page.tsx b/apps/app/src/app/[locale]/blocks/[hash]/page.tsx new file mode 100644 index 00000000..007e3119 --- /dev/null +++ b/apps/app/src/app/[locale]/blocks/[hash]/page.tsx @@ -0,0 +1,60 @@ +import Details from '@/components/app/Blocks/Details'; +import { nanoToMilli } from '@/utils/app/libs'; +import { Suspense } from 'react'; +import HashLoading from '@/components/app/skeleton/blocks/hash'; +import { getRequest } from '@/utils/app/api'; +import { unstable_setRequestLocale } from 'next-intl/server'; + +export default async function Hash({ + params, +}: { + params: { hash: string; locale: string }; +}) { + unstable_setRequestLocale(params?.locale); + + const [hashData, priceData] = await fetchHashAndPriceData(params.hash); + + return ( + <> +
+ }> +
+ +
+
+ + ); +} + +async function fetchHashAndPriceData(hash: string) { + const hashDataPromise = fetchHashData(hash); + + const priceDataPromise = hashDataPromise.then(async (data) => { + const timestamp = data?.blocks?.[0]?.block_timestamp; + return timestamp ? fetchPriceData(timestamp) : null; + }); + + const [hashData, priceData] = await Promise.all([ + hashDataPromise, + priceDataPromise, + ]); + return [hashData, priceData]; +} + +async function fetchHashData(hash: string) { + return getRequest(`blocks/${hash}`); +} + +async function fetchPriceData(timestamp: any) { + const formattedTimestamp = formatTimestamp(timestamp); + return getRequest(`stats/price?date=${formattedTimestamp}`); +} + +function formatTimestamp(timestamp: any) { + return new Date(nanoToMilli(timestamp)).toISOString().split('T')[0]; +} diff --git a/apps/app/src/app/[locale]/layout.tsx b/apps/app/src/app/[locale]/layout.tsx new file mode 100644 index 00000000..a120f3f9 --- /dev/null +++ b/apps/app/src/app/[locale]/layout.tsx @@ -0,0 +1,91 @@ +import { NextIntlClientProvider } from 'next-intl'; +import Layout from '@/components/app/Layouts'; +import { getRequest } from '@/utils/app/api'; +import { + getLocale, + getMessages, + unstable_setRequestLocale, +} from 'next-intl/server'; + +export default async function ProviderLayout({ + children, +}: { + children: React.ReactNode; + params: any; +}) { + const locale = await getLocale(); + const messages = await getMessages({ locale }); + unstable_setRequestLocale(locale); + + const [stats, blocks] = await Promise.all([ + getRequest(`stats`), + getRequest(`blocks/latest?limit=1`), + ]); + + const handleFilterAndKeyword = async ( + keyword: string, + filter: string, + returnPath: any, + ) => { + 'use server'; + + if (keyword.includes('.')) { + keyword = keyword.toLowerCase(); + } + + const res = await getRequest(`search${filter}?keyword=${keyword}`); + + const data = { + blocks: [], + txns: [], + accounts: [], + receipts: [], + }; + + if (res?.blocks?.length) { + if (returnPath) { + return { type: 'block', path: res.blocks[0].block_hash }; + } + data.blocks = res.blocks; + } + + if (res?.txns?.length) { + if (returnPath) { + return { type: 'txn', path: res.txns[0].transaction_hash }; + } + data.txns = res.txns; + } + + if (res?.receipts?.length) { + if (returnPath) { + return { + type: 'txn', + path: res.receipts[0].originated_from_transaction_hash, + }; + } + data.receipts = res.receipts; + } + + if (res?.accounts?.length) { + if (returnPath) { + return { type: 'address', path: res.accounts[0].account_id }; + } + data.accounts = res.accounts; + } + + return returnPath ? null : data; + }; + return ( + <> + + + {children} + + + + ); +} diff --git a/apps/app/src/app/_not-found-component.tsx b/apps/app/src/app/_not-found-component.tsx new file mode 100644 index 00000000..219a9e9e --- /dev/null +++ b/apps/app/src/app/_not-found-component.tsx @@ -0,0 +1,11 @@ +'use client'; +import Error from 'next/error'; +export default function NotFound() { + return ( + + + + + + ); +} diff --git a/apps/app/src/app/global-error.tsx b/apps/app/src/app/global-error.tsx new file mode 100644 index 00000000..25d22385 --- /dev/null +++ b/apps/app/src/app/global-error.tsx @@ -0,0 +1,50 @@ +'use client'; +import Link from 'next/link'; +import { useEffect } from 'react'; + +export const Content = () => { + return ( + <> +
+ {`Sorry! We encountered an unexpected error.`} +
+ + + ); +}; + +export default function GlobalError({ + error, +}: { + error: Error; + reset: () => void; +}) { + useEffect(() => { + // Log the error to an error reporting service + console.error(error); + }, [error]); + + return ( + + +
+
+
+
+ 500 +
+ +
+
+
+
+ + + ); +} diff --git a/apps/app/src/app/icon.ico b/apps/app/src/app/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..bf45fe875c1cb79a8798cb464cde85c0fce7eb96 GIT binary patch literal 15406 zcmeI336#xcAIER98#^J<*hMkC5g}V8WG`E`P$?;eETu#wdzM7hQPwE3lQofj36+qc zF?NI5mwTW0^L?7Xb6t0snOE<7-p<@}p7Wpkzt8e}e$Q|H{+@BU?sDDj%9YE-Gtku| zy~|bA<#GiE{`I|VZkOwG-US6E{$ASU+LqttDoY=RFygQGJpL~~#+Y=pyKY51zu$f0 z#EELOvg)hvfBf-BnT;Da_MSd{`h@<~erkSjiV&cpFcTXaYoel}%#Iy9Oru7P+~dcOUvmEZ`2gQJLPA3Fe(}W@ zGm8}~me8b06Lam_HMU_4a~t{_kH=&7?%iwZ)vFi1fB*iLzT@@%$dMy8`91Qr*IqND zM~}Aa>iO)m&l=`8F)=ZwbLY-x+O%nt#3SE14j(?;ux8Dg(ds*P>{v5&=uiV6%(vfu zYhHTkCBxoLpFVxe@ZrPfFg}Ctcz7HH?bmki-fg0zqs>PjePrH$|9uk|7iU(lUTwN{ z>n0v}X3d&4n(^s;$DciWHrspey|?+5S6(rZk&z}oKHknlU;Fn5AADeH*RCD@+i$Q&h$ zYtJ`LhifoK2QGq`904(^UT$? zYuB!ZC(W_heesXKV)J84moDvL9RrPqeH;91$@C41 zRf1NoT=^ruEIJ?{z>_m)PQ@2d#3{!oO`3GBV#SK_l`2&-qehJ~oPoJ;;ew3^kOliZ zckY}aPB8-p3^3)&l{3|PN618d5re(w`rRaT=JbTl? z?^ec6ojO&E7;Q<14jsaD4(ZdUH~I4AGsH-CZN)s!M}I4hP(0<;ry$#2@^-AyzPzD_4&B@y8!mz_-Flt?B!o1p+wZZqR^i4D+>O-rLGy;`+IW zk%m3_-D`s=T4OiGMxX;pkDnb5h&K6LNi{XDj*8|!ED zw_o3P^veakLx@Ymv^Q*;jWxyZkt0XiHKqUPr|H$Jm!(Z{xX$9Kr=Buv)~vBH`nq-N z?D{Xi{PH>MbZ6%En``)4KY;aLdH(t5FNl70$jZ6S-J#*3haNKMrI|Nxo{fuj9+Jg2 zZQ7W|jT@U~%a&O^lx-y5KF#{F1Ie<<^vj6+)*m-+T(ERVdsg0}k3)lU2y!DEPdhrH z`2MG#elo3EwX!@Ce@c}qmB9HNME=S#{FXMr;RF5d!j9a}zSl~Bq({huJp+dZ>6`Ri z`tSXb+=*Y0KKiK1n>Vj)P&oc^27SnYlmC&ufaacWz4cZodypM5Cr+HW!S*>e$9sLz z1Fx;laz1Wyz+>2yCiF>`>^l_FKOK84zIE%?ugRanbq)gu4z#kUJjmg>v$kvwKHK^L z`*jgo#^WOj(C@Z>&{^Agvj2>nL(NsIR&8k5uwjJeY~H-NnKNgO)k)cU@-r)w z^fjM;`l%s5wri6cg<&5S;{VFCcCze_v#$4(u~|6hI{1WTFTVKV1^h}pyfBYE@`w>F zZQHgr_$%32>wD4HIPA@7?Ds6$amL@2lX}meoWGeP6Eu`3Mi`0@+}E>b&-2*aaBO2V zJc)&-Xyoi#zkdDBz^kp;?l;gE#Xxr~w_~omIo~|L|NeUry4eH!Fcp8l44q%cb1}4y z=L|Y=Cc-;%(2}KV$=SbmAJIVzpyj0%L>3Dv9wkQ8_pG$PWnFI?(*924z(0Wl!byN= zU0rBtI0;Nh`=oIojRR>MNaMhNjRVAMisv%YvLrTPkis=noG+x5Xx0#(skOAeaMatz zj_Q-xS2#@oae01lnG!t9DMsgANm@a2t{l`?v?tB0J>Jp%B+je6sxnPjV+~qST9WyO zexuzBPF5X^qAmGkZ?MXt;49<7ZzhA+P5JJ-?ECA-(gxujh*87ZnX$*Nq2jY0;4~p+Czx1R@Ch~zPRUq$Z2hF3Xhpr~CKSIuT z2}~&b?YG~K0waqWHf&e~cx4#1wP5hf&E$Yn$U(bPKdi+sXhyhr3HWo*8+#0 zKW5CB-@ze5$}0E2Hsm)Vjphs)CksH zhrR6yzEgxjsga|s?7ti}hrVDYo2c)fefZ&rV^w$19<-N2g$j9uy>mXMS+iyqPsXO- zfcIY~*v}ur=Y)&FD2^TB}uzz70=ataYgMx@})Z$!dy$1ENQS`ap1Fu!8ZFq zM|os9Rag^aGhrW#;SV};ALC18`zZB>Xw@CkrAue!Nq0{q1FA9k`-om)?)qJrpk&M6 z9<=|NGiO@t?!gBiG}L&`L-%~_weZo5N%^bWy=Saqhm7Qa^A4ZW~n9nzICLiUWUS7h!sgAJ-v$RgE__xvtuSk0=kigiOAsH} zJ>W;_{?{EI$&G3`>QDXE*3DGAa?ZhfuhM1d0r#(LfBae`d!LHk71o=q`ij3jFjlcy z4QkBeI(P2;r+k$5Aem5|OEnPg3fX<=98~Yo9whg|`(;~-7AZ|NZw%=3;aQj&pe$8uBEE zR)2jG>92>Ko<dTvZ7m*qXgD|9AHQvX6aBJXs+k`= zc+l3#M8E2JufF=KrJs6P3^kfX(BJe9&|e$=Pioh$U5H{c)h1PgRBcXnU3w~>OO|v7 z+Jk6T{Z@ZV2V^6~Ysr*!M|)7Lq}q!3Efv3t-tNPct< zioda0hS=E3xB6%g(ruj|{>1Kq*v*jV*mIG7GtLbkt`fhDga4%%maO_}67(yc$cKzK zCr;mmT*fKJ*EuV8k?c5jP)|pe#8cTG>9BY%x}A@64$>iFLAwW?tMpv)D7ir_cOOqu zI~srw%fqbtUss_je8RcF7|K6D=9yJ(l~m%Wlrz+UNoRvdZfLE`o?iS_9_!h5eh zWW>)@M-N7zpT7{RL}TkbiYKJ2*gJclK|0}WmmI$9o$Rdig525OJ(4exox<+K;sZ~C zzf5Ou4H(01|2z9(PUXlsiREi??lXvEej|R1#3$Q3ce3S@1>N_NPnKU&o~R}{k$;lD z$Tle^)qOPO@c6Q5?xzJ4Z+?TnZ6{e}ojW2oz8uiJ@Gvjy=zio_@TkMwAGnI%C15)& z-b4Iu;~{cn8_(!254o-I66=$dqe#}3FOsW76XzU7hh~E}He>$6v{c_~@TJ$^cg;`B zjn3Agw*L;cdKt0(abkvOWZ5nHQ>;v0A#I%CF+4cO3;=vGr& zp}(7UXFue`>9D6+IO~$gdnaUN8Zq@&`DpfWn%L$NdT|xI7^%kjgyWMhL-!eC`{TrS zJK6g@VGY>k%KCo*X#ZPe#-Z8YlQo5b7GN(GuqTbN+kMG(rV{ThC2!tF+lMbYz;iqP zdKGch=fnu{tYP-Q~>}0 literal 0 HcmV?d00001 diff --git a/apps/app/src/app/layout.tsx b/apps/app/src/app/layout.tsx new file mode 100644 index 00000000..8e9985e8 --- /dev/null +++ b/apps/app/src/app/layout.tsx @@ -0,0 +1,70 @@ +import '@/styles/globals.css'; +import { ThemeProvider } from 'next-themes'; +import Script from 'next/script'; +import { env } from 'next-runtime-env'; +import '../../public/common.css'; +import Head from 'next/head'; +import { Manrope } from 'next/font/google'; +import { unstable_setRequestLocale } from 'next-intl/server'; + +interface paramTypes { + children: React.ReactNode; + params: { locale: string }; +} + +const manrope = Manrope({ + weight: ['200', '300', '400', '500', '600'], + subsets: ['latin'], + display: 'swap', +}); + +export default async function RootLayout({ + children, + params: { locale }, +}: paramTypes) { + unstable_setRequestLocale(locale); + + return ( + + + + + + + + + {children} + + + + ); +} + +export const revalidate = 5; diff --git a/apps/app/src/app/not-found.ts b/apps/app/src/app/not-found.ts new file mode 100644 index 00000000..0d9acc42 --- /dev/null +++ b/apps/app/src/app/not-found.ts @@ -0,0 +1 @@ +export { default } from './_not-found-component'; diff --git a/apps/app/src/components/ActiveLink.tsx b/apps/app/src/components/ActiveLink.tsx index babd88a0..078ab02a 100644 --- a/apps/app/src/components/ActiveLink.tsx +++ b/apps/app/src/components/ActiveLink.tsx @@ -1,8 +1,13 @@ -import Link, { LinkProps } from 'next/link'; -import { useRouter } from 'next/router'; +import { Link, usePathname } from '@/i18n/routing'; import React, { Children, ReactElement, ReactNode } from 'react'; import { UrlObject } from 'url'; +type LinkProps = Omit & { + locale?: any; + className?: any; + legacyBehavior?: boolean; +}; + interface ActiveLinkProps extends LinkProps { children: ReactNode; activeClassName?: string; @@ -15,11 +20,12 @@ const ActiveLink = ({ activeClassName, inActiveClassName, href, + legacyBehavior, ...props }: ActiveLinkProps) => { - const { asPath } = useRouter(); + const asPath = usePathname(); - const child = Children.only(children) as ReactElement; + const child = Children?.only(children) as ReactElement; const childClassName = child?.props?.className || ' '; const hrefString = typeof href === 'string' ? href : href.pathname || ''; diff --git a/apps/app/src/components/Address/AccessKeyRow.tsx b/apps/app/src/components/Address/AccessKeyRow.tsx index b7fccdcf..c83a4c70 100644 --- a/apps/app/src/components/Address/AccessKeyRow.tsx +++ b/apps/app/src/components/Address/AccessKeyRow.tsx @@ -1,4 +1,5 @@ import useRpc from '@/hooks/useRpc'; +import { Link } from '@/i18n/routing'; import { formatTimestampToString, getTimeAgoString, @@ -8,8 +9,7 @@ import { } from '@/utils/libs'; import { AccessInfo, AccountContractInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; import { useEffect, useState } from 'react'; interface Props { @@ -18,7 +18,7 @@ interface Props { } const AccessKeyRow = ({ accessKey, showWhen }: Props) => { - const { t } = useTranslation(); + const t = useTranslations(); const [keyInfo, setKeyInfo] = useState({} as AccessInfo); const { viewAccessKey } = useRpc(); const createdTime = accessKey?.created?.block_timestamp diff --git a/apps/app/src/components/Address/AccessKeys.tsx b/apps/app/src/components/Address/AccessKeys.tsx index a70de317..9026091e 100644 --- a/apps/app/src/components/Address/AccessKeys.tsx +++ b/apps/app/src/components/Address/AccessKeys.tsx @@ -7,6 +7,7 @@ import Paginator from '../common/Paginator'; import { useRouter } from 'next/router'; import AccessKeyRow from './AccessKeyRow'; import { AccountContractInfo } from '@/utils/types'; +import { useIntlRouter, usePathname } from '@/i18n/routing'; interface Props { keys: AccountContractInfo[]; @@ -17,17 +18,21 @@ interface Props { const AccessKeys = ({ keys, count, error, tab }: Props) => { const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const [showWhen, setShowWhen] = useState(true); const toggleShowWhen = () => setShowWhen((s) => !s); const onOrder = () => { const currentOrder = router.query.order || 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; + const { id, locale, ...rest } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: { - ...router.query, + ...rest, order: newOrder, }, }); diff --git a/apps/app/src/components/Address/Balance.tsx b/apps/app/src/components/Address/Balance.tsx index 53950b67..92a75af6 100644 --- a/apps/app/src/components/Address/Balance.tsx +++ b/apps/app/src/components/Address/Balance.tsx @@ -12,12 +12,12 @@ import { import WarningIcon from '../Icons/WarningIcon'; import FaExternalLinkAlt from '../Icons/FaExternalLinkAlt'; import TokenHoldings from '../common/TokenHoldings'; -import Link from 'next/link'; import { networkId } from '@/utils/config'; -import useTranslation from 'next-translate/useTranslation'; import Skeleton from '../skeleton/common/Skeleton'; import { useRouter } from 'next/router'; import TokenImage from '../common/TokenImage'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const Balance = ({ accountData, @@ -39,7 +39,7 @@ const Balance = ({ }: any) => { const router = useRouter(); const { id } = router.query; - const { t } = useTranslation(); + const t = useTranslations(); const balance = accountData?.amount ?? ''; const nearPrice = statsData?.near_price ?? ''; @@ -94,7 +94,7 @@ const Balance = ({

- {t ? t('address:overview') : 'Overview'} + {t ? t('overview') : 'Overview'}

{tokenData?.name && (
@@ -117,7 +117,7 @@ const Balance = ({
- {t ? t('address:balance') : 'Balance'}: + {t ? t('balance') : 'Balance'}:
{loading ? ( @@ -134,7 +134,7 @@ const Balance = ({ statsData?.near_price && (
- {t ? t('address:value') : 'Value:'} + {t ? t('value') : 'Value:'}
{loading ? ( @@ -163,7 +163,7 @@ const Balance = ({ )}
- {t ? t('address:tokens') : 'Tokens:'} + {t ? t('tokens') : 'Tokens:'}

- {t ? t('address:moreInfo') : 'Account information'} + {t ? t('moreInfo') : 'Account information'}

- Staked {t ? t('address:balance') : 'Balance'}: + Staked {t ? t('balance') : 'Balance'}:
{loading ? (
@@ -204,7 +204,7 @@ const Balance = ({
- {t ? t('address:storageUsed') : 'Storage Used'}: + {t ? t('storageUsed') : 'Storage Used'}:
{loading ? (
diff --git a/apps/app/src/components/Address/Contract/ContractCode.tsx b/apps/app/src/components/Address/Contract/ContractCode.tsx index 11835228..19e3f3ec 100644 --- a/apps/app/src/components/Address/Contract/ContractCode.tsx +++ b/apps/app/src/components/Address/Contract/ContractCode.tsx @@ -1,6 +1,5 @@ import Question from '@/components/Icons/Question'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import { useState } from 'react'; import VerifiedData from './VerifiedData'; import VerificationStatus from './VerificationStatus'; @@ -9,6 +8,7 @@ import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; import { verifierConfig } from '@/utils/config'; import { parseGitHubLink, parseLink } from '@/utils/libs'; +import { Link } from '@/i18n/routing'; type ContractCodeProps = { error: string | null; diff --git a/apps/app/src/components/Address/Contract/Info.tsx b/apps/app/src/components/Address/Contract/Info.tsx index 90f8c3f9..3856cdab 100644 --- a/apps/app/src/components/Address/Contract/Info.tsx +++ b/apps/app/src/components/Address/Contract/Info.tsx @@ -1,9 +1,8 @@ -import Link from 'next/link'; - import { Tooltip } from '@reach/tooltip'; import Question from '@/components/Icons/Question'; import { convertToUTC, nanoToMilli } from '@/utils/libs'; import { ContractCodeInfo, DeploymentsInfo } from '@/utils/types'; +import { Link } from '@/i18n/routing'; interface Props { contract: ContractCodeInfo; diff --git a/apps/app/src/components/Address/Contract/VerificationStatus.tsx b/apps/app/src/components/Address/Contract/VerificationStatus.tsx index c3969e91..1903c9ea 100644 --- a/apps/app/src/components/Address/Contract/VerificationStatus.tsx +++ b/apps/app/src/components/Address/Contract/VerificationStatus.tsx @@ -1,8 +1,8 @@ import ArrowDown from '@/components/Icons/ArrowDown'; import FaCheckCircle from '@/components/Icons/FaCheckCircle'; import FaExclamationCircle from '@/components/Icons/FaExclamationCircle'; +import { Link } from '@/i18n/routing'; import { ContractMetadata, VerificationData } from '@/utils/types'; -import Link from 'next/link'; import React from 'react'; type VerificationStatusProps = { diff --git a/apps/app/src/components/Address/Contract/ViewOrChange.tsx b/apps/app/src/components/Address/Contract/ViewOrChange.tsx index 0b944a23..fc6f100c 100644 --- a/apps/app/src/components/Address/Contract/ViewOrChange.tsx +++ b/apps/app/src/components/Address/Contract/ViewOrChange.tsx @@ -11,11 +11,11 @@ import ArrowRight from '@/components/Icons/ArrowRight'; import { Tooltip } from '@reach/tooltip'; import Question from '@/components/Icons/Question'; import CloseCircle from '@/components/Icons/CloseCircle'; -import Link from 'next/link'; import { useVmStore } from '@/stores/vm'; import { useRouter } from 'next/router'; import { fetcher } from '@/hooks/useFetch'; import { useAuthStore } from '@/stores/auth'; +import { Link } from '@/i18n/routing'; interface Props { connected?: boolean; diff --git a/apps/app/src/components/Address/Contract/ViewOrChangeAbi.tsx b/apps/app/src/components/Address/Contract/ViewOrChangeAbi.tsx index 2d34c617..27dcc15c 100644 --- a/apps/app/src/components/Address/Contract/ViewOrChangeAbi.tsx +++ b/apps/app/src/components/Address/Contract/ViewOrChangeAbi.tsx @@ -13,8 +13,8 @@ import ArrowRight from '@/components/Icons/ArrowRight'; import { Tooltip } from '@reach/tooltip'; import CloseCircle from '@/components/Icons/CloseCircle'; import Question from '@/components/Icons/Question'; -import Link from 'next/link'; import { useAuthStore } from '@/stores/auth'; +import { Link } from '@/i18n/routing'; interface Props { index: number; diff --git a/apps/app/src/components/Address/NFTTransactions.tsx b/apps/app/src/components/Address/NFTTransactions.tsx index daf7867e..496b8c35 100644 --- a/apps/app/src/components/Address/NFTTransactions.tsx +++ b/apps/app/src/components/Address/NFTTransactions.tsx @@ -1,11 +1,9 @@ import { localFormat, truncateString } from '@/utils/libs'; import { TransactionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import { useRouter } from 'next/router'; import { useState } from 'react'; import TxnStatus from '../common/Status'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import { Menu, MenuButton, MenuList } from '@reach/menu-button'; import Filter from '../Icons/Filter'; import Clock from '../Icons/Clock'; @@ -19,6 +17,8 @@ import FaInbox from '../Icons/FaInbox'; import TokenImage from '../common/TokenImage'; import dynamic from 'next/dynamic'; import TableSummary from '../common/TableSummary'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialForm = { event: '', @@ -42,14 +42,16 @@ const NFTTransactions = ({ cursor, tab, }: NftTokenTxnsProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const { id } = router.query; const [page, setPage] = useState(1); const [form, setForm] = useState(initialForm); const [showAge, setShowAge] = useState(true); const [address, setAddress] = useState(''); - const errorMessage = t ? t('txns:noTxns') : ' No transactions found!'; + const errorMessage = t ? t('noTxns') : ' No transactions found!'; const toggleShowAge = () => setShowAge((s) => !s); const onChange = (e: any) => { @@ -62,11 +64,13 @@ const NFTTransactions = ({ const onOrder = () => { const currentOrder = router.query.order || 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; + const { id, locale, ...rest } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: { - ...router.query, + ...rest, order: newOrder, }, }); @@ -78,8 +82,8 @@ const NFTTransactions = ({ setPage(1); const { event, involved } = form; - const { pathname, query } = router; - const { cursor, p, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, locale, id, ...updatedQuery } = query; const queryParams = { ...(event && { event: event.toUpperCase() }), @@ -88,19 +92,21 @@ const NFTTransactions = ({ const finalQuery = { ...updatedQuery, ...queryParams }; - router.push({ pathname, query: finalQuery }); + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: finalQuery }); }; const onClear = (e: React.MouseEvent) => { const { name } = e.currentTarget; - const { cursor, p, ...restQuery } = router.query; + const { cursor, p, locale, id, ...restQuery } = router.query; setPage(1); setForm((f) => ({ ...f, [name]: '' })); const { [name]: _, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -108,10 +114,12 @@ const NFTTransactions = ({ const onAllClear = () => { setForm(initialForm); - const { cursor, event, p, involved, ...newQuery } = router.query; + const { cursor, event, p, involved, locale, id, ...newQuery } = + router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -138,7 +146,7 @@ const NFTTransactions = ({ 'pl-5 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: <>{t ? t('txns:hash') : 'TXN HASH'}, + header: <>{t ? t('hash') : 'TXN HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( @@ -165,7 +173,7 @@ const NFTTransactions = ({ header: ( - {t ? t('txns:type') : 'METHOD'}{' '} + {t ? t('type') : 'METHOD'}{' '} @@ -183,7 +191,7 @@ const NFTTransactions = ({ className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -260,15 +268,15 @@ const NFTTransactions = ({ <> {row?.involved_account_id === row?.affected_account_id ? ( - {t ? t('txns:txnSelf') : 'SELF'} + {t ? t('txnSelf') : 'SELF'} ) : Number(row?.delta_amount) < 0 ? ( - {t ? t('txns:txnOut') : 'OUT'} + {t ? t('txnOut') : 'OUT'} ) : ( - {t ? t('txns:txnIn') : 'IN'} + {t ? t('txnIn') : 'IN'} )} @@ -289,9 +297,7 @@ const NFTTransactions = ({ value={form.involved} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -301,7 +307,7 @@ const NFTTransactions = ({ className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -438,10 +444,10 @@ const NFTTransactions = ({ > {showAge ? t - ? t('txns:age') + ? t('age') : 'AGE' : t - ? t('txns:ageDT') + ? t('ageDT') : 'DATE TIME (UTC)'} {showAge && ( @@ -470,8 +476,18 @@ const NFTTransactions = ({ function removeCursor() { const queryParams = router.query; - const { cursor, order, p, tab, keyword, query, filter, ...rest } = - queryParams; + const { + cursor, + order, + p, + tab, + locale, + keyword, + query, + filter, + id, + ...rest + } = queryParams; return rest; } diff --git a/apps/app/src/components/Address/Receipts.tsx b/apps/app/src/components/Address/Receipts.tsx index 17fbceb6..2132f6be 100644 --- a/apps/app/src/components/Address/Receipts.tsx +++ b/apps/app/src/components/Address/Receipts.tsx @@ -7,11 +7,9 @@ import { } from '@/utils/libs'; import { txnMethod } from '@/utils/near'; import { TransactionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import { useRouter } from 'next/router'; import React, { useState } from 'react'; import TxnStatus from '../common/Status'; -import Link from 'next/link'; import { Tooltip } from '@reach/tooltip'; import Filter from '../Icons/Filter'; import Skeleton from '../skeleton/common/Skeleton'; @@ -24,6 +22,8 @@ import ErrorMessage from '../common/ErrorMessage'; import FaInbox from '../Icons/FaInbox'; import TimeStamp from '../common/TimeStamp'; import TableSummary from '../common/TableSummary'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialForm = { action: '', @@ -41,8 +41,10 @@ interface TxnsProps { } const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const { id } = router.query; const [page, setPage] = useState(1); const [form, setForm] = useState(initialForm); @@ -80,8 +82,8 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { setPage(1); const { action, method, from, to } = form; - const { pathname, query } = router; - const { cursor, p, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, locale, id, ...updatedQuery } = query; const queryParams = { ...(action && { action }), @@ -92,17 +94,20 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { const finalQuery = { ...updatedQuery, ...queryParams }; - router.push({ pathname, query: finalQuery }); + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: finalQuery }); }; const onOrder = () => { const currentOrder = router.query.order || 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; + const { id, locale, ...rest } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: { - ...router.query, + ...rest, order: newOrder, }, }); @@ -122,14 +127,15 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { const { name } = e.currentTarget; setPage(1); - const { cursor, p, ...restQuery } = router.query; + const { cursor, p, locale, id, ...restQuery } = router.query; if (name === 'type') { setForm((prev) => ({ ...prev, action: '', method: '' })); const { action, method, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); return; @@ -137,8 +143,9 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { setForm((f) => ({ ...f, [name]: '' })); const { [name]: _, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); } @@ -147,11 +154,22 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { const onAllClear = () => { setForm(initialForm); - const { cursor, action, p, method, from, to, block, ...newQuery } = - router.query; + const { + cursor, + action, + p, + method, + from, + to, + block, + locale, + id, + ...newQuery + } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -194,7 +212,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { }, { - header: {t ? t('txns:hash') : 'TXN HASH'}, + header: {t ? t('hash') : 'TXN HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( @@ -229,7 +247,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { header: ( - {t ? t('txns:type') : 'METHOD'}{' '} + {t ? t('type') : 'METHOD'}{' '} @@ -247,7 +265,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white dark:text-black text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -281,7 +299,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-2 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: {t ? t('txns:depositValue') : 'DEPOSIT VALUE'}, + header: {t ? t('depositValue') : 'DEPOSIT VALUE'}, key: 'deposit', cell: (row: TransactionInfo) => ( @@ -297,7 +315,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-4 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('txns:txnFee') : 'TXN FEE'}, + header: {t ? t('txnFee') : 'TXN FEE'}, key: 'transaction_fee', cell: (row: TransactionInfo) => ( @@ -317,7 +335,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { <> - {t ? t('txns:from') : 'FROM'}{' '} + {t ? t('from') : 'FROM'}{' '} @@ -327,9 +345,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { value={form.from} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -339,7 +355,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -392,15 +408,15 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { cell: (row: TransactionInfo) => { return row?.predecessor_account_id === row?.receiver_account_id ? ( - {t ? t('txns:txnSelf') : 'SELF'} + {t ? t('txnSelf') : 'SELF'} ) : id === row?.predecessor_account_id ? ( - {t ? t('txns:txnOut') : 'OUT'} + {t ? t('txnOut') : 'OUT'} ) : ( - {t ? t('txns:txnIn') : 'IN'} + {t ? t('txnIn') : 'IN'} ); }, @@ -410,7 +426,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { <> - {t ? t('txns:to') : 'To'}{' '} + {t ? t('to') : 'To'}{' '} @@ -420,9 +436,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { value={form.to} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -432,7 +446,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -480,7 +494,7 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-2 text-sm text-nearblue-600 dark:text-neargray-10 font-medium w-44', }, { - header: {t ? t('txns:blockHeight') : ' BLOCK HEIGHT'}, + header: {t ? t('blockHeight') : ' BLOCK HEIGHT'}, key: 'block_height', cell: (row: TransactionInfo) => ( @@ -517,10 +531,10 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { > {showAge ? t - ? t('txns:age') + ? t('age') : 'AGE' : t - ? t('txns:ageDT') + ? t('ageDT') : 'DATE TIME (UTC)'} {showAge && ( @@ -548,8 +562,18 @@ const Receipts = ({ txns, count, error, cursor, tab }: TxnsProps) => { function removeCursor() { const queryParams = router.query; - const { cursor, order, p, tab, keyword, query, filter, ...rest } = - queryParams; + const { + cursor, + order, + p, + tab, + locale, + keyword, + query, + filter, + id, + ...rest + } = queryParams; return rest; } diff --git a/apps/app/src/components/Address/TokenTransactions.tsx b/apps/app/src/components/Address/TokenTransactions.tsx index ed0dfdbf..9aef51ae 100644 --- a/apps/app/src/components/Address/TokenTransactions.tsx +++ b/apps/app/src/components/Address/TokenTransactions.tsx @@ -1,10 +1,8 @@ import { localFormat, truncateString } from '@/utils/libs'; import { tokenAmount } from '@/utils/near'; import { TransactionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import { useState } from 'react'; import TxnStatus from '../common/Status'; -import Link from 'next/link'; import { Tooltip } from '@reach/tooltip'; import { Menu, MenuButton, MenuList } from '@reach/menu-button'; import Filter from '../Icons/Filter'; @@ -20,6 +18,8 @@ import Table from '../common/Table'; import TokenImage from '../common/TokenImage'; import TimeStamp from '../common/TimeStamp'; import TableSummary from '../common/TableSummary'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialForm = { event: '', @@ -41,23 +41,27 @@ const TokenTransactions = ({ cursor, tab, }: TokenTxnsProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const [showAge, setShowAge] = useState(true); const [page, setPage] = useState(1); const { id } = router.query; const [form, setForm] = useState(initialForm); - const errorMessage = t ? t('txns:noTxns') : 'No transactions found!'; + const errorMessage = t ? t('noTxns') : 'No transactions found!'; const [address, setAddress] = useState(''); const onOrder = () => { const currentOrder = router.query.order || 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; + const { id, locale, ...rest } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: { - ...router.query, + ...rest, order: newOrder, }, }); @@ -88,8 +92,8 @@ const TokenTransactions = ({ setPage(1); const { event, involved } = form; - const { pathname, query } = router; - const { cursor, p, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, locale, id, ...updatedQuery } = query; const queryParams = { ...(event && { event: event.toUpperCase() }), @@ -97,20 +101,21 @@ const TokenTransactions = ({ }; const finalQuery = { ...updatedQuery, ...queryParams }; - - router.push({ pathname, query: finalQuery }); + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: finalQuery }); }; const onClear = (e: React.MouseEvent) => { const { name } = e.currentTarget; - const { cursor, p, ...restQuery } = router.query; + const { cursor, p, locale, id, ...restQuery } = router.query; setPage(1); setForm((f) => ({ ...f, [name]: '' })); const { [name]: _, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -118,10 +123,12 @@ const TokenTransactions = ({ const onAllClear = () => { setForm(initialForm); - const { cursor, event, p, involved, ...newQuery } = router.query; + const { cursor, event, p, involved, locale, id, ...newQuery } = + router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -139,7 +146,7 @@ const TokenTransactions = ({ 'pl-5 py-3 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: <>{t ? t('txns:hash') : 'TXN HASH'}, + header: <>{t ? t('hash') : 'TXN HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( @@ -167,7 +174,7 @@ const TokenTransactions = ({ <> - {t ? t('txns:type') : 'METHOD'}{' '} + {t ? t('type') : 'METHOD'}{' '} @@ -185,7 +192,7 @@ const TokenTransactions = ({ className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white dark:text-black text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -263,15 +270,15 @@ const TokenTransactions = ({ <> {row?.involved_account_id === row?.affected_account_id ? ( - {t ? t('txns:txnSelf') : 'SELF'} + {t ? t('txnSelf') : 'SELF'} ) : Number(row?.delta_amount) < 0 ? ( - {t ? t('txns:txnOut') : 'OUT'} + {t ? t('txnOut') : 'OUT'} ) : ( - {t ? t('txns:txnIn') : 'IN'} + {t ? t('txnIn') : 'IN'} )} @@ -292,9 +299,7 @@ const TokenTransactions = ({ value={form.involved} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -304,7 +309,7 @@ const TokenTransactions = ({ className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -446,10 +451,10 @@ const TokenTransactions = ({ > {showAge ? t - ? t('txns:age') + ? t('age') : 'AGE' : t - ? t('txns:ageDT') + ? t('ageDT') : 'DATE TIME (UTC)'} {showAge && ( @@ -477,8 +482,18 @@ const TokenTransactions = ({ function removeCursor() { const queryParams = router.query; - const { cursor, order, p, tab, keyword, query, filter, ...rest } = - queryParams; + const { + cursor, + order, + p, + tab, + locale, + keyword, + query, + filter, + id, + ...rest + } = queryParams; return rest; } diff --git a/apps/app/src/components/Address/Transactions.tsx b/apps/app/src/components/Address/Transactions.tsx index f30c2731..ef10c605 100644 --- a/apps/app/src/components/Address/Transactions.tsx +++ b/apps/app/src/components/Address/Transactions.tsx @@ -7,11 +7,9 @@ import { } from '@/utils/libs'; import { txnMethod } from '@/utils/near'; import { TransactionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import { useRouter } from 'next/router'; import React, { useState } from 'react'; import TxnStatus from '../common/Status'; -import Link from 'next/link'; import { Tooltip } from '@reach/tooltip'; import Filter from '../Icons/Filter'; import Skeleton from '../skeleton/common/Skeleton'; @@ -24,6 +22,8 @@ import ErrorMessage from '../common/ErrorMessage'; import FaInbox from '../Icons/FaInbox'; import TimeStamp from '../common/TimeStamp'; import TableSummary from '../common/TableSummary'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialForm = { action: '', @@ -41,13 +41,15 @@ interface TxnsProps { } const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const { id } = router.query; const [page, setPage] = useState(1); const [form, setForm] = useState(initialForm); const [showAge, setShowAge] = useState(true); - const errorMessage = t ? t('txns:noTxns') : ' No transactions found!'; + const errorMessage = t ? t('noTxns') : ' No transactions found!'; const [address, setAddress] = useState(''); const toggleShowAge = () => setShowAge((s) => !s); @@ -81,8 +83,8 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { setPage(1); const { action, method, from, to } = form; - const { pathname, query } = router; - const { cursor, p, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, locale, id, ...updatedQuery } = query; const queryParams = { ...(action && { action }), @@ -92,18 +94,19 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { }; const finalQuery = { ...updatedQuery, ...queryParams }; - - router.push({ pathname, query: finalQuery }); + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: finalQuery }); }; const onOrder = () => { const currentOrder = router.query.order || 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; - - router.push({ - pathname: router.pathname, + const { id, locale, ...rest } = router.query; + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: { - ...router.query, + ...rest, order: newOrder, }, }); @@ -123,14 +126,15 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { const { name } = e.currentTarget; setPage(1); - const { cursor, p, ...restQuery } = router.query; + const { cursor, p, locale, id, ...restQuery } = router.query; if (name === 'type') { setForm((prev) => ({ ...prev, action: '', method: '' })); const { action, method, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); return; @@ -138,8 +142,9 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { setForm((f) => ({ ...f, [name]: '' })); const { [name]: _, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); } @@ -148,11 +153,22 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { const onAllClear = () => { setForm(initialForm); - const { cursor, action, p, method, from, to, block, ...newQuery } = - router.query; + const { + cursor, + action, + p, + method, + from, + to, + block, + locale, + id, + ...newQuery + } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -170,7 +186,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'pl-5 py-2 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: {t ? t('txns:hash') : 'TXN HASH'}, + header: {t ? t('hash') : 'TXN HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( @@ -197,7 +213,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { header: ( - {t ? t('txns:type') : 'METHOD'}{' '} + {t ? t('type') : 'METHOD'}{' '} @@ -215,7 +231,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white dark:text-black text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -249,7 +265,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-2 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: {t ? t('txns:depositValue') : 'DEPOSIT VALUE'}, + header: {t ? t('depositValue') : 'DEPOSIT VALUE'}, key: 'deposit', cell: (row: TransactionInfo) => ( @@ -265,7 +281,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-4 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('txns:txnFee') : 'TXN FEE'}, + header: {t ? t('txnFee') : 'TXN FEE'}, key: 'transaction_fee', cell: (row: TransactionInfo) => ( @@ -285,7 +301,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { <> - {t ? t('txns:from') : 'FROM'}{' '} + {t ? t('from') : 'FROM'}{' '} @@ -295,9 +311,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { value={form.from} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -307,7 +321,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -361,15 +375,15 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { cell: (row: TransactionInfo) => { return row?.signer_account_id === row?.receiver_account_id ? ( - {t ? t('txns:txnSelf') : 'SELF'} + {t ? t('txnSelf') : 'SELF'} ) : id === row?.signer_account_id ? ( - {t ? t('txns:txnOut') : 'OUT'} + {t ? t('txnOut') : 'OUT'} ) : ( - {t ? t('txns:txnIn') : 'IN'} + {t ? t('txnIn') : 'IN'} ); }, @@ -379,7 +393,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { <> - {t ? t('txns:to') : 'To'}{' '} + {t ? t('to') : 'To'}{' '} @@ -389,9 +403,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { value={form.to} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -401,7 +413,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -449,7 +461,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { 'px-4 py-2 text-sm text-nearblue-600 dark:text-neargray-10 font-medium w-44', }, { - header: {t ? t('txns:blockHeight') : ' BLOCK HEIGHT'}, + header: {t ? t('blockHeight') : ' BLOCK HEIGHT'}, key: 'block_height', cell: (row: TransactionInfo) => ( @@ -486,10 +498,10 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { > {showAge ? t - ? t('txns:age') + ? t('age') : 'AGE' : t - ? t('txns:ageDT') + ? t('ageDT') : 'DATE TIME (UTC)'} {showAge && ( @@ -517,7 +529,7 @@ const Transactions = ({ txns, count, error, cursor, tab }: TxnsProps) => { function removeCursor() { const queryParams = router.query; - const { cursor, order, p, tab, keyword, query, filter, ...rest } = + const { cursor, order, p, tab, locale, keyword, query, filter, ...rest } = queryParams; return rest; } diff --git a/apps/app/src/components/Blocks/Detail.tsx b/apps/app/src/components/Blocks/Detail.tsx index f84c376f..68f43793 100644 --- a/apps/app/src/components/Blocks/Detail.tsx +++ b/apps/app/src/components/Blocks/Detail.tsx @@ -7,15 +7,15 @@ import { localFormat, nanoToMilli, } from '@/utils/libs'; -import Link from 'next/link'; import ErrorMessage from '../common/ErrorMessage'; import FileSlash from '../Icons/FileSlash'; import { gasPrice } from '@/utils/near'; -import useTranslation from 'next-translate/useTranslation'; import { BlocksInfo } from '@/utils/types'; import { networkId } from '@/utils/config'; import ListCheck from '../Icons/ListCheck'; import FaCheckCircle from '../Icons/FaCheckCircle'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { hash: string; @@ -26,7 +26,7 @@ interface Props { const Details = (props: Props) => { const { hash, blockInfo, price, error } = props; - const { t } = useTranslation(); + const t = useTranslations(); interface Props { children?: string; @@ -53,9 +53,9 @@ const Details = (props: Props) => {

{t ? ( <> - {t('blocks:block.heading.0')} + {t('block.heading.0')} - {t('blocks:block.heading.1', { + {t('block.heading.1', { block: block?.block_height ? localFormat(block?.block_height.toString()) : '', @@ -120,14 +120,12 @@ const Details = (props: Props) => {
{networkId === 'testnet' && (
- {t - ? t('blocks:testnetNotice') - : '[ This is a Testnet block only ]'} + {t ? t('testnetNotice') : '[ This is a Testnet block only ]'}
)}
- {t ? t('blocks:block.height') : 'Block Height'} + {t ? t('block.height') : 'Block Height'}
{block?.block_height @@ -137,7 +135,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.hash') : 'Hash'} + {t ? t('block.hash') : 'Hash'}
{block?.block_hash} @@ -146,7 +144,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.timestamp') : 'Timestamp'} + {t ? t('block.timestamp') : 'Timestamp'}
{block?.block_timestamp && @@ -160,14 +158,14 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.transactions.0') : 'Transactions'} + {t ? t('block.transactions.0') : 'Transactions'}
{block?.transactions_agg?.count && (
{t ? ( <> - {t('blocks:block.transactions.1', { + {t('block.transactions.1', { txns: block?.transactions_agg?.count ? localFormat( block?.transactions_agg?.count?.toString(), @@ -176,7 +174,7 @@ const Details = (props: Props) => { })}   - {t('blocks:block.transactions.2', { + {t('block.transactions.2', { receipts: block?.receipts_agg?.count ? localFormat(block?.receipts_agg?.count?.toString()) : block?.receipts_agg?.count?.toString() ?? '', @@ -205,7 +203,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.author') : 'Author'} + {t ? t('block.author') : 'Author'}
{
- {t ? t('blocks:block.gasUsed') : 'GAS Used'} + {t ? t('block.gasUsed') : 'GAS Used'}
{gasUsed @@ -228,7 +226,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.gasLimit') : 'Gas Limit'} + {t ? t('block.gasLimit') : 'Gas Limit'}
{gasLimit @@ -238,7 +236,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.gasPrice') : 'GAS Price'} + {t ? t('block.gasPrice') : 'GAS Price'}
{block?.gas_price @@ -248,7 +246,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.gasFee') : 'Gas Fee'} + {t ? t('block.gasFee') : 'Gas Fee'}
{gasUsed && block?.gas_price @@ -259,7 +257,7 @@ const Details = (props: Props) => {
- {t ? t('blocks:block.parenthash') : 'Parent Hash'} + {t ? t('block.parenthash') : 'Parent Hash'}
{ {networkId === 'mainnet' && price && (
- {t ? t('blocks:block.price') : 'Price'} + {t ? t('block.price') : 'Price'}
{price ? `$${dollarFormat(price)} / Ⓝ` : 'N/A'} diff --git a/apps/app/src/components/Blocks/Latest.tsx b/apps/app/src/components/Blocks/Latest.tsx index d7813b1f..c46c2d21 100644 --- a/apps/app/src/components/Blocks/Latest.tsx +++ b/apps/app/src/components/Blocks/Latest.tsx @@ -1,8 +1,6 @@ import React from 'react'; -import Link from 'next/link'; import 'react-perfect-scrollbar/dist/css/styles.css'; import PerfectScrollbar from 'react-perfect-scrollbar'; -import useTranslation from 'next-translate/useTranslation'; import Skeleton from '../skeleton/common/Skeleton'; import { BlocksInfo } from '@/utils/types'; import { @@ -12,6 +10,8 @@ import { nanoToMilli, } from '@/utils/libs'; import { Tooltip } from '@reach/tooltip'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { blocks: BlocksInfo[]; @@ -19,7 +19,7 @@ interface Props { } const LatestBlocks = ({ blocks, error }: Props) => { - const { t } = useTranslation(); + const t = useTranslations(); return ( <> @@ -27,12 +27,12 @@ const LatestBlocks = ({ blocks, error }: Props) => { {!blocks && error && (
- {t ? t('home:error') : 'Error!'} + {t ? t('error') : 'Error!'}
)} {!error && blocks?.length === 0 && (
- {t ? t('home:noBlocks') : 'No blocks found'} + {t ? t('noBlocks') : 'No blocks found'}
)} {error && blocks?.length === 0 && ( @@ -115,13 +115,13 @@ const LatestBlocks = ({ blocks, error }: Props) => {
- {t ? t('home:blockMiner') : 'Author'}  + {t ? t('blockMiner') : 'Author'}  - {block?.author_account_id} + {block?.author_account_id}
{block?.transactions_agg?.count @@ -158,11 +158,10 @@ const LatestBlocks = ({ blocks, error }: Props) => { )} {blocks && blocks?.length > 0 && (
- - View all blocks + + + View all blocks +
)} diff --git a/apps/app/src/components/Blocks/List.tsx b/apps/app/src/components/Blocks/List.tsx index b323ac07..6951037a 100644 --- a/apps/app/src/components/Blocks/List.tsx +++ b/apps/app/src/components/Blocks/List.tsx @@ -7,13 +7,13 @@ import { localFormat, shortenAddress, } from '@/utils/libs'; -import Link from 'next/link'; import { Tooltip } from '@reach/tooltip'; import Clock from '../Icons/Clock'; import FaInbox from '../Icons/FaInbox'; -import useTranslation from 'next-translate/useTranslation'; import Table from '../common/Table'; import TimeStamp from '../common/TimeStamp'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface ListProps { data: { @@ -27,10 +27,10 @@ interface ListProps { } const List = ({ data, totalCount, error }: ListProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const [showAge, setShowAge] = useState(true); const [page, setPage] = useState(1); - const errorMessage = t ? t('blocks:noBlocks') : 'No blocks!'; + const errorMessage = t ? t('noBlocks') : 'No blocks!'; const [address, setAddress] = useState(''); const onHandleMouseOver = (e: any, id: string) => { @@ -51,7 +51,7 @@ const List = ({ data, totalCount, error }: ListProps) => { const columns: any = [ { - header: {t ? t('blocks:blocks') : 'BLOCK'}, + header: {t ? t('blocks') : 'BLOCK'}, key: 'block_hash', cell: (row: BlocksInfo) => ( @@ -88,7 +88,7 @@ const List = ({ data, totalCount, error }: ListProps) => { > {showAge ? ( <> - {t ? t('blocks:age') : 'AGE'} + {t ? t('age') : 'AGE'} ) : ( @@ -108,7 +108,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10 w-48', }, { - header: {t ? t('blocks:txn') : 'TXN'}, + header: {t ? t('txn') : 'TXN'}, key: 'count', cell: (row: BlocksInfo) => ( @@ -128,7 +128,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('blocks:block.receipt') : 'RECEIPT'}, + header: {t ? t('block.receipt') : 'RECEIPT'}, key: 'count', cell: (row: BlocksInfo) => ( @@ -143,7 +143,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('blocks:miner') : 'AUTHOR'}, + header: {t ? t('miner') : 'AUTHOR'}, key: 'author_account_id', cell: (row: BlocksInfo) => ( @@ -167,7 +167,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('blocks:block.gasUsed') : 'GAS USED'}, + header: {t ? t('block.gasUsed') : 'GAS USED'}, key: 'gas_used', cell: (row: BlocksInfo) => ( @@ -182,7 +182,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('blocks:block.gasLimit') : 'GAS LIMIT'}, + header: {t ? t('block.gasLimit') : 'GAS LIMIT'}, key: 'gas_limit', cell: (row: BlocksInfo) => ( {convertToMetricPrefix(row?.chunks_agg?.gas_limit ?? 0)}gas @@ -193,7 +193,7 @@ const List = ({ data, totalCount, error }: ListProps) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('blocks:block.gasFee') : 'GAS FEE'}, + header: {t ? t('block.gasFee') : 'GAS FEE'}, key: 'gas_price', cell: (row: BlocksInfo) => ( @@ -216,7 +216,7 @@ const List = ({ data, totalCount, error }: ListProps) => { {blocks && blocks.length > 0 && (

{t - ? t('blocks:listing', { + ? t('listing', { from: start?.block_height ? localFormat && localFormat(start?.block_height) : start?.block_height ?? '', diff --git a/apps/app/src/components/Charts/Chart.tsx b/apps/app/src/components/Charts/Chart.tsx index b2af45d0..4698f991 100644 --- a/apps/app/src/components/Charts/Chart.tsx +++ b/apps/app/src/components/Charts/Chart.tsx @@ -1,15 +1,15 @@ import { useEffect, useMemo, useState } from 'react'; -import Link from 'next/link'; import Question from '../Icons/Question'; import SwitchButton from '../SwitchButton'; import { yoctoToNear } from '@/utils/libs'; import { ChartConfig, ChartStat, ChartTypeInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; import { useTheme } from 'next-themes'; -import useTranslation from 'next-translate/useTranslation'; import { networkId } from '@/utils/config'; import Skeleton from '../skeleton/common/Skeleton'; import Image from 'next/legacy/image'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { chartTypes?: string; @@ -22,7 +22,7 @@ interface Props { const Chart = (props: Props) => { const { chartTypes, poweredBy, chartsData } = props; - const { t } = useTranslation(); + const t = useTranslations(); const { theme } = useTheme(); const [chartConfig, setChartConfig] = useState(null); const [chartInfo, setChartInfo] = useState({ @@ -40,58 +40,56 @@ const Chart = (props: Props) => { const charts = [ { link: '/charts/near-price', - text: t ? t('charts:nearPrice.heading') : 'Near Daily Price (USD) Chart', + text: t ? t('nearPrice.heading') : 'Near Daily Price (USD) Chart', image: `/images/charts/near-price.svg`, image_dark: `/images/charts/near-price_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/market-cap', - text: t - ? t('charts:marketCap.heading') - : 'Near Market Capitalization Chart', + text: t ? t('marketCap.heading') : 'Near Market Capitalization Chart', image: `/images/charts/market-cap.svg`, image_dark: `/images/charts/market-cap_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/near-supply', - text: t ? t('charts:nearSupply.heading') : 'Near Supply Growth Chart', + text: t ? t('nearSupply.heading') : 'Near Supply Growth Chart', image: `/images/charts/near-supply.svg`, image_dark: `/images/charts/near-supply_dark.svg`, exclude: false, }, { link: '/charts/txns', - text: t ? t('charts:txns.heading') : 'Near Daily Transactions Chart', + text: t ? t('txns.heading') : 'Near Daily Transactions Chart', image: `/images/charts/txns.svg`, image_dark: `/images/charts/txns_dark.svg`, exclude: false, }, { link: '/charts/blocks', - text: t ? t('charts:blocks.heading') : 'New Blocks', + text: t ? t('blocks.heading') : 'New Blocks', image: `/images/charts/blocks.svg`, image_dark: `/images/charts/blocks_dark.svg`, exclude: false, }, { link: '/charts/addresses', - text: t ? t('charts:addresses.heading') : 'Near Unique Accounts Chart', + text: t ? t('addresses.heading') : 'Near Unique Accounts Chart', image: `/images/charts/addresses.svg`, image_dark: `/images/charts/addresses_dark.svg`, exclude: false, }, { link: '/charts/txn-fee', - text: t ? t('charts:txnFee.heading') : 'Transaction Fee Chart', + text: t ? t('txnFee.heading') : 'Transaction Fee Chart', image: `/images/charts/txn-fee.svg`, image_dark: `/images/charts/txn-fee_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/txn-volume', - text: t ? t('charts:txnVolume.heading') : 'Transaction Volume Chart', + text: t ? t('txnVolume.heading') : 'Transaction Volume Chart', image: `/images/charts/txn-volume.svg`, image_dark: `/images/charts/txn-volume_dark.svg`, exclude: `${networkId}` === 'testnet', @@ -523,7 +521,7 @@ const Chart = (props: Props) => {

- {t('charts:otherHeading')} + {t('otherHeading')}

)} diff --git a/apps/app/src/components/Charts/TpsChart.tsx b/apps/app/src/components/Charts/TpsChart.tsx index d6130a05..5c48863c 100644 --- a/apps/app/src/components/Charts/TpsChart.tsx +++ b/apps/app/src/components/Charts/TpsChart.tsx @@ -1,14 +1,14 @@ import { useEffect, useState } from 'react'; import SwitchButton from '../SwitchButton'; import Question from '../Icons/Question'; -import Link from 'next/link'; import { chartDataInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; import { useTheme } from 'next-themes'; -import useTranslation from 'next-translate/useTranslation'; import { networkId } from '@/utils/config'; import Image from 'next/image'; import Skeleton from '../skeleton/common/Skeleton'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { chartTypes: string; @@ -21,7 +21,7 @@ interface Props { const TpsChart = (props: Props) => { const { chartTypes, poweredBy, data } = props; const { theme } = useTheme(); - const { t } = useTranslation(); + const t = useTranslations(); const [chartTpsData, setChartTpsData] = useState([]); const [logView, setLogView] = useState(false); @@ -33,58 +33,56 @@ const TpsChart = (props: Props) => { const charts = [ { link: '/charts/near-price', - text: t ? t('charts:nearPrice.heading') : 'Near Daily Price (USD) Chart', + text: t ? t('nearPrice.heading') : 'Near Daily Price (USD) Chart', image: `/images/charts/near-price.svg`, image_dark: `/images/charts/near-price_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/market-cap', - text: t - ? t('charts:marketCap.heading') - : 'Near Market Capitalization Chart', + text: t ? t('marketCap.heading') : 'Near Market Capitalization Chart', image: `/images/charts/market-cap.svg`, image_dark: `/images/charts/market-cap_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/near-supply', - text: t ? t('charts:nearSupply.heading') : 'Near Supply Growth Chart', + text: t ? t('nearSupply.heading') : 'Near Supply Growth Chart', image: `/images/charts/near-supply.svg`, image_dark: `/images/charts/near-supply_dark.svg`, exclude: false, }, { link: '/charts/txns', - text: t ? t('charts:txns.heading') : 'Near Daily Transactions Chart', + text: t ? t('txns.heading') : 'Near Daily Transactions Chart', image: `/images/charts/txns.svg`, image_dark: `/images/charts/txns_dark.svg`, exclude: false, }, { link: '/charts/blocks', - text: t ? t('charts:blocks.heading') : 'New Blocks', + text: t ? t('blocks.heading') : 'New Blocks', image: `/images/charts/blocks.svg`, image_dark: `/images/charts/blocks_dark.svg`, exclude: false, }, { link: '/charts/addresses', - text: t ? t('charts:addresses.heading') : 'Near Unique Accounts Chart', + text: t ? t('addresses.heading') : 'Near Unique Accounts Chart', image: `/images/charts/addresses.svg`, image_dark: `/images/charts/addresses_dark.svg`, exclude: false, }, { link: '/charts/txn-fee', - text: t ? t('charts:txnFee.heading') : 'Transaction Fee Chart', + text: t ? t('txnFee.heading') : 'Transaction Fee Chart', image: `/images/charts/txn-fee.svg`, image_dark: `/images/charts/txn-fee_dark.svg`, exclude: `${networkId}` === 'testnet', }, { link: '/charts/txn-volume', - text: t ? t('charts:txnVolume.heading') : 'Transaction Volume Chart', + text: t ? t('txnVolume.heading') : 'Transaction Volume Chart', image: `/images/charts/txn-volume.svg`, image_dark: `/images/charts/txn-volume_dark.svg`, exclude: `${networkId}` === 'testnet', @@ -308,7 +306,7 @@ const TpsChart = (props: Props) => {

- {t('charts:otherHeading')} + {t('otherHeading')}

)} diff --git a/apps/app/src/components/Error.tsx b/apps/app/src/components/Error.tsx index 003083df..75411646 100644 --- a/apps/app/src/components/Error.tsx +++ b/apps/app/src/components/Error.tsx @@ -1,22 +1,20 @@ +import { Link } from '@/i18n/routing'; import Head from 'next/head'; -import Trans from 'next-translate/Trans'; -import DynamicNamespaces from 'next-translate/DynamicNamespaces'; -import Link from 'next/link'; -export const Content = ({ i18nKey = '404:description' }) => { +export const Content = () => { return ( - + <>
- ]} /> + {`Sorry! We encountered an unexpected error.`}
-
+ ); }; diff --git a/apps/app/src/components/Layouts/Footer.tsx b/apps/app/src/components/Layouts/Footer.tsx index eb817a10..927c5107 100644 --- a/apps/app/src/components/Layouts/Footer.tsx +++ b/apps/app/src/components/Layouts/Footer.tsx @@ -1,10 +1,10 @@ -import Link from 'next/link'; import Image from 'next/legacy/image'; -import useTranslation from 'next-translate/useTranslation'; import { useTheme } from 'next-themes'; import Arrow from '../Icons/Arrow'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const Footer = () => { - const { t } = useTranslation('common'); + const t = useTranslations(); const { theme } = useTheme(); const currentDate = new Date(); return ( diff --git a/apps/app/src/components/Layouts/FormContact.tsx b/apps/app/src/components/Layouts/FormContact.tsx index c7ad391b..7e12b515 100644 --- a/apps/app/src/components/Layouts/FormContact.tsx +++ b/apps/app/src/components/Layouts/FormContact.tsx @@ -1,5 +1,4 @@ import { useEffect, useRef, useState } from 'react'; -import useTranslation from 'next-translate/useTranslation'; import ArrowDown from '../Icons/ArrowDown'; import LoadingCircular from '../common/LoadingCircular'; import { toast } from 'react-toastify'; @@ -8,6 +7,7 @@ import { env } from 'next-runtime-env'; import { Turnstile } from '@marsidev/react-turnstile'; import type { TurnstileInstance } from '@marsidev/react-turnstile'; import { useTheme } from 'next-themes'; +import { useTranslations } from 'next-intl'; interface Props { selectValue?: string; @@ -17,7 +17,7 @@ const siteKey = env('NEXT_PUBLIC_TURNSTILE_SITE_KEY'); const FormContact = ({ selectValue }: Props) => { const { theme } = useTheme(); - const { t } = useTranslation('contact'); + const t = useTranslations(); const [loading, setLoading] = useState(false); const [name, setName] = useState(''); diff --git a/apps/app/src/components/Layouts/Header.tsx b/apps/app/src/components/Layouts/Header.tsx index 4000ce59..881d47b2 100644 --- a/apps/app/src/components/Layouts/Header.tsx +++ b/apps/app/src/components/Layouts/Header.tsx @@ -1,8 +1,5 @@ -import Link from 'next/link'; import Image from 'next/legacy/image'; -import { useRouter } from 'next/router'; import React, { useMemo, useState } from 'react'; -import useTranslation from 'next-translate/useTranslation'; import { useAuthStore } from '@/stores/auth'; import { useTheme } from 'next-themes'; import Collapse from '../Collapse'; @@ -15,6 +12,9 @@ import { dollarFormat, nanoToMilli } from '@/utils/libs'; import User from '../Icons/User'; import { BlocksInfo, Stats } from '@/utils/types'; import Search from '../common/Search'; +import { useTranslations } from 'next-intl'; +import { Link, routing, usePathname } from '@/i18n/routing'; +import NextLink from 'next/link'; const menus = [ { @@ -78,10 +78,6 @@ const menus = [ ]; const languages = [ - { - title: 'English', - locale: 'en', - }, { title: '한국어', locale: 'kr', @@ -151,8 +147,8 @@ const Header = ({ }: Props) => { /* eslint-disable @next/next/no-img-element */ - const router = useRouter(); - const { t } = useTranslation('common'); + const pathname = usePathname(); + const t = useTranslations(); const [open, setOpen] = useState(false); const { theme, setTheme } = useTheme(); const requestSignInWithWallet = useAuthStore( @@ -180,13 +176,29 @@ const Header = ({ return true; }, [block]); - const showSearch = router.pathname !== '/'; + const showSearch = pathname !== '/'; const userLoading = false; const onSignOut = () => { logOut(); }; const nearPrice = stats?.near_price ?? ''; + + type LinkProps = Omit & { + href: string; + locale: any; + children: any; + className: any; + }; + + const IntlLink: React.FC = (props) => { + if (!routing?.locales?.includes(props.locale)) { + console.error(`Invalid locale: ${props.locale}`); + return null; + } + + return ; + }; return (
{!status && ( @@ -338,14 +350,13 @@ const Header = ({ @@ -366,7 +377,7 @@ const Header = ({ activeClassName="text-green-500 dark:text-green-250" > - {t(submenu.title)} + {t(submenu.title)} @@ -405,13 +416,25 @@ const Header = ({ )} > @@ -425,13 +448,23 @@ const Header = ({ diff --git a/apps/app/src/components/NodeExplorer/Delegators.tsx b/apps/app/src/components/NodeExplorer/Delegators.tsx index d658c603..8da3d245 100644 --- a/apps/app/src/components/NodeExplorer/Delegators.tsx +++ b/apps/app/src/components/NodeExplorer/Delegators.tsx @@ -3,7 +3,6 @@ import { DelegatorInfo, RewardFraction, ValidatorStatus } from '@/utils/types'; import { CurrentEpochValidatorInfo, ValidatorDescription } from 'nb-types'; import { useEffect, useRef, useState } from 'react'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import useRpc from '@/hooks/useRpc'; import Image from 'next/image'; import { useRouter } from 'next/router'; @@ -15,6 +14,7 @@ import Table from '../common/Table'; import ErrorMessage from '../common/ErrorMessage'; import FaInbox from '../Icons/FaInbox'; import { useRpcStore } from '@/stores/rpc'; +import { Link } from '@/i18n/routing'; interface Props { accountId: string; diff --git a/apps/app/src/components/Tokens/FT/FAQ.tsx b/apps/app/src/components/Tokens/FT/FAQ.tsx index d8bfbb19..7e197117 100644 --- a/apps/app/src/components/Tokens/FT/FAQ.tsx +++ b/apps/app/src/components/Tokens/FT/FAQ.tsx @@ -1,6 +1,7 @@ import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { Link } from '@/i18n/routing'; import { convertToUTC, dollarFormat, @@ -16,7 +17,6 @@ import { HoldersPropsInfo, Token, } from '@/utils/types'; -import Link from 'next/link'; interface Props { id: string; diff --git a/apps/app/src/components/Tokens/FT/Holders.tsx b/apps/app/src/components/Tokens/FT/Holders.tsx index 7d7dc095..f2252811 100644 --- a/apps/app/src/components/Tokens/FT/Holders.tsx +++ b/apps/app/src/components/Tokens/FT/Holders.tsx @@ -1,5 +1,4 @@ import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import { HoldersPropsInfo, Token } from '../../../utils/types'; import { getTimeAgoString, @@ -14,6 +13,7 @@ import { useRouter } from 'next/router'; import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; +import { Link } from '@/i18n/routing'; interface Props { token: Token; diff --git a/apps/app/src/components/Tokens/FT/Overview.tsx b/apps/app/src/components/Tokens/FT/Overview.tsx index dd9bfc14..f49125b5 100644 --- a/apps/app/src/components/Tokens/FT/Overview.tsx +++ b/apps/app/src/components/Tokens/FT/Overview.tsx @@ -8,7 +8,6 @@ import { nanoToMilli, } from '@/utils/libs'; import Big from 'big.js'; -import Link from 'next/link'; import { useFetch } from '@/hooks/useFetch'; import { Tooltip } from '@reach/tooltip'; import Skeleton from '@/components/skeleton/common/Skeleton'; @@ -17,6 +16,7 @@ import WarningIcon from '@/components/Icons/WarningIcon'; import Question from '@/components/Icons/Question'; import Links from '@/components/common/Links'; import { useRouter } from 'next/router'; +import { Link } from '@/i18n/routing'; interface Props { stats: StatusInfo; diff --git a/apps/app/src/components/Tokens/FT/TokenFilter.tsx b/apps/app/src/components/Tokens/FT/TokenFilter.tsx index 22aba28f..6f4399e3 100644 --- a/apps/app/src/components/Tokens/FT/TokenFilter.tsx +++ b/apps/app/src/components/Tokens/FT/TokenFilter.tsx @@ -1,11 +1,11 @@ import { FtInfo, FtsInfo, InventoryInfo, TokenListInfo } from '@/utils/types'; import Big from 'big.js'; import { useEffect, useState } from 'react'; -import Link from 'next/link'; import { dollarFormat, localFormat } from '@/utils/libs'; import useRpc from '@/hooks/useRpc'; import FaAddressBook from '@/components/Icons/FaAddressBook'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { Link } from '@/i18n/routing'; interface Props { id: string; diff --git a/apps/app/src/components/Tokens/FT/Transfers.tsx b/apps/app/src/components/Tokens/FT/Transfers.tsx index 59392e5d..9f9d9874 100644 --- a/apps/app/src/components/Tokens/FT/Transfers.tsx +++ b/apps/app/src/components/Tokens/FT/Transfers.tsx @@ -1,9 +1,7 @@ import { TransactionInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; import { useState } from 'react'; import { localFormat } from '@/utils/libs'; -import Link from 'next/link'; import Big from 'big.js'; import { tokenAmount } from '@/utils/near'; import TxnStatus from '@/components/common/Status'; @@ -16,6 +14,8 @@ import Filters from '@/components/common/Filters'; import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; interface Props { txns: TransactionInfo[]; @@ -27,9 +27,11 @@ interface Props { const Transfers = ({ txns, count, cursor, error, tab }: Props) => { const router = useRouter(); - const { t } = useTranslation(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); + const t = useTranslations(); const [showAge, setShowAge] = useState(true); - const errorMessage = t ? t('txns:noTxns') : 'No transactions found!'; + const errorMessage = t ? t('noTxns') : 'No transactions found!'; const [address, setAddress] = useState(''); const [page, setPage] = useState(1); @@ -46,10 +48,11 @@ const Transfers = ({ txns, count, cursor, error, tab }: Props) => { }; const onAllClear = () => { - const { cursor, a, p, ...newQuery } = router.query; + const { cursor, a, p, locale, ...newQuery } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; @@ -207,7 +210,7 @@ const Transfers = ({ txns, count, cursor, error, tab }: Props) => { cell: (row: TransactionInfo) => row?.involved_account_id === row?.affected_account_id ? ( - {t ? t('txns:txnSelf') : 'Self'} + {t ? t('txnSelf') : 'Self'} ) : (
@@ -326,11 +329,11 @@ const Transfers = ({ txns, count, cursor, error, tab }: Props) => { > {showAge ? ( <> - {t ? t('token:fts.age') : 'AGE'} + {t ? t('fts.age') : 'AGE'} ) : ( - <> {t ? t('token:fts.ageDT') : 'DATE TIME (UTC)'} + <> {t ? t('fts.ageDT') : 'DATE TIME (UTC)'} )} @@ -349,7 +352,7 @@ const Transfers = ({ txns, count, cursor, error, tab }: Props) => { function removeCursor() { const queryParams = router.query; - const { cursor, order, p, tab, keyword, query, filter, ...rest } = + const { cursor, order, p, tab, locale, keyword, query, filter, ...rest } = queryParams; return rest; } diff --git a/apps/app/src/components/Tokens/FTList.tsx b/apps/app/src/components/Tokens/FTList.tsx index 80f4e942..d9ca1243 100644 --- a/apps/app/src/components/Tokens/FTList.tsx +++ b/apps/app/src/components/Tokens/FTList.tsx @@ -7,10 +7,8 @@ import { serialNumber, } from '@/utils/libs'; import { Sorting, Token } from '@/utils/types'; -import Link from 'next/link'; import { fetcher } from '@/hooks/useFetch'; import { useRouter } from 'next/router'; -import useTranslation from 'next-translate/useTranslation'; import { Tooltip } from '@reach/tooltip'; import debounce from 'lodash/debounce'; import TokenImage from '@/components/common/TokenImage'; @@ -21,6 +19,8 @@ import SortIcon from '@/components/Icons/SortIcon'; import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialForm = { search: '', @@ -43,14 +43,16 @@ interface Props { } const List = ({ data, tokensCount, error }: Props) => { - const { t } = useTranslation('token'); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const { page, search }: any = router.query; const pagination = { page: page ? Number(page) : 1, per_page: 50 }; const [searchResults, setSearchResults] = useState([]); const [selectedIndex, setSelectedIndex] = useState(-1); const [value, setValue] = useState(undefined); - const errorMessage = t ? t('token:fts.top.empty') : 'No tokens found!'; + const errorMessage = t ? t('fts.top.empty') : 'No tokens found!'; const [isOpen, setIsOpen] = useState(false); const containerRef: any = useRef(null); const [form, setForm] = useState(initialForm); @@ -106,9 +108,10 @@ const List = ({ data, tokensCount, error }: Props) => { }; const onFilter = () => { - const { pathname, query } = router; - const { page, ...updatedQuery } = query; - router.push({ pathname, query: { ...updatedQuery, ...form, page: 1 } }); + const { query } = router; + const { page, locale, ...updatedQuery } = query; + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: { ...updatedQuery, ...form, page: 1 } }); }; useEffect(() => { @@ -125,14 +128,16 @@ const List = ({ data, tokensCount, error }: Props) => { if (selectedIndex > -1) { const selectedToken = searchResults[selectedIndex]; if (selectedToken) { - router.push(`/token/${selectedToken.contract}`); + // @ts-ignore: Unreachable code error + intlRouter.push(`/token/${selectedToken.contract}`); } } else { if (value) { onFilter(); setSelectedIndex(-1); } else if (Object.keys(router.query).length > 0) { - router.push(`/tokens`); + // @ts-ignore: Unreachable code error + intlRouter.push(`/tokens`); } } } @@ -157,13 +162,16 @@ const List = ({ data, tokensCount, error }: Props) => { const onOrder = (sortKey: string) => { setSorting((state) => { const { - pathname, - query: { order, ...updatedQuery }, + query: { order, locale, ...updatedQuery }, } = router; const newOrder: 'asc' | 'desc' = (order ?? 'desc') === 'asc' ? 'desc' : 'asc'; const newState: Sorting = { ...state, sort: sortKey, order: newOrder }; - router.push({ pathname, query: { ...updatedQuery, order: newOrder } }); + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname, + query: { ...updatedQuery, order: newOrder }, + }); return newState; }); }; @@ -181,7 +189,7 @@ const List = ({ data, tokensCount, error }: Props) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider', }, { - header: {t ? t('token:fts.top.token') : 'TOKEN'}, + header: {t ? t('fts.top.token') : 'TOKEN'}, key: 'name', cell: (row: Token) => ( <> @@ -211,7 +219,7 @@ const List = ({ data, tokensCount, error }: Props) => { 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider', }, { - header: {t ? t('token:fts.top.price') : 'PRICE'}, + header: {t ? t('fts.top.price') : 'PRICE'}, key: 'price', cell: (row: Token) => ( @@ -230,7 +238,7 @@ const List = ({ data, tokensCount, error }: Props) => { { header: ( - {t ? t('token:fts.top.change') : 'CHANGE'} (%) + {t ? t('fts.top.change') : 'CHANGE'} (%) ), key: 'change_24', @@ -257,7 +265,7 @@ const List = ({ data, tokensCount, error }: Props) => { 'px-6 py-2 w-60 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider', }, { - header: {t ? t('token:fts.top.volume') : 'VOLUME'} (24H), + header: {t ? t('fts.top.volume') : 'VOLUME'} (24H), key: 'volume_24h', cell: (row: Token) => ( diff --git a/apps/app/src/components/Tokens/FTTransfers.tsx b/apps/app/src/components/Tokens/FTTransfers.tsx index da8783ee..ea3216b4 100644 --- a/apps/app/src/components/Tokens/FTTransfers.tsx +++ b/apps/app/src/components/Tokens/FTTransfers.tsx @@ -8,17 +8,17 @@ import { import { tokenAmount } from '@/utils/near'; import { useEffect, useState } from 'react'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import Big from 'big.js'; import TxnStatus from '@/components/common/Status'; import FaLongArrowAltRight from '@/components/Icons/FaLongArrowAltRight'; import Clock from '@/components/Icons/Clock'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; -import useTranslation from 'next-translate/useTranslation'; import Table from '@/components/common/Table'; import TokenImage from '@/components/common/TokenImage'; import useRpc from '@/hooks/useRpc'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface ListProps { data: { @@ -36,10 +36,10 @@ interface ListProps { } const Transfers = ({ data, totalCount, error, status }: ListProps) => { - const { t } = useTranslation(); + const t = useTranslations(); const [showAge, setShowAge] = useState(true); const [page, setPage] = useState(1); - const errorMessage = t ? t('txns:noTxns') : 'No transactions found!'; + const errorMessage = t ? t('noTxns') : 'No transactions found!'; const [address, setAddress] = useState(''); const { getBlockDetails } = useRpc(); const [timestamp, setTimeStamp] = useState(''); @@ -88,7 +88,7 @@ const Transfers = ({ data, totalCount, error, status }: ListProps) => { 'pl-5 py-3 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', }, { - header: {t ? t('token:fts.hash') : 'HASH'}, + header: {t ? t('fts.hash') : 'HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( { > {showAge ? t - ? t('token:fts.age') + ? t('fts.age') : 'AGE' : t - ? t('token:fts.ageDT') + ? t('fts.ageDT') : 'DATE TIME (UTC)'} {showAge && ( diff --git a/apps/app/src/components/Tokens/NFT/Detail.tsx b/apps/app/src/components/Tokens/NFT/Detail.tsx index 76679b40..db41fbfb 100644 --- a/apps/app/src/components/Tokens/NFT/Detail.tsx +++ b/apps/app/src/components/Tokens/NFT/Detail.tsx @@ -1,7 +1,6 @@ import { shortenAddress } from '@/utils/libs'; import { SpamToken, Token, TransactionInfo } from '@/utils/types'; import { useState } from 'react'; -import Link from 'next/link'; import { Accordion, AccordionButton, @@ -16,6 +15,7 @@ import ArrowUp from '@/components/Icons/ArrowUp'; import ArrowDown from '@/components/Icons/ArrowDown'; import Question from '@/components/Icons/Question'; import TokenTransfers from './TokenTransfers'; +import { Link } from '@/i18n/routing'; interface Props { id: string; tid?: string; diff --git a/apps/app/src/components/Tokens/NFT/Holders.tsx b/apps/app/src/components/Tokens/NFT/Holders.tsx index b9594451..128d5c1a 100644 --- a/apps/app/src/components/Tokens/NFT/Holders.tsx +++ b/apps/app/src/components/Tokens/NFT/Holders.tsx @@ -2,6 +2,7 @@ import ErrorMessage from '@/components/common/ErrorMessage'; import Table from '@/components/common/Table'; import FaInbox from '@/components/Icons/FaInbox'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { Link } from '@/i18n/routing'; import { getTimeAgoString, holderPercentage, @@ -11,7 +12,6 @@ import { } from '@/utils/libs'; import { HoldersPropsInfo, Token } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; import { useRouter } from 'next/router'; interface Props { diff --git a/apps/app/src/components/Tokens/NFT/Inventory.tsx b/apps/app/src/components/Tokens/NFT/Inventory.tsx index 04bbc486..9c327157 100644 --- a/apps/app/src/components/Tokens/NFT/Inventory.tsx +++ b/apps/app/src/components/Tokens/NFT/Inventory.tsx @@ -3,9 +3,9 @@ import Paginator from '@/components/common/Paginator'; import { NFTImage } from '@/components/common/TokenImage'; import FaInbox from '@/components/Icons/FaInbox'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { Link } from '@/i18n/routing'; import { localFormat } from '@/utils/libs'; import { Token } from '@/utils/types'; -import Link from 'next/link'; interface Props { token: Token; diff --git a/apps/app/src/components/Tokens/NFT/TokenTransfers.tsx b/apps/app/src/components/Tokens/NFT/TokenTransfers.tsx index e8a8e838..354ed05e 100644 --- a/apps/app/src/components/Tokens/NFT/TokenTransfers.tsx +++ b/apps/app/src/components/Tokens/NFT/TokenTransfers.tsx @@ -7,9 +7,7 @@ import { } from '@/utils/libs'; import { TransactionInfo } from '@/utils/types'; import { useState } from 'react'; -import Link from 'next/link'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; import TxnStatus from '@/components/common/Status'; import FaLongArrowAltRight from '@/components/Icons/FaLongArrowAltRight'; import Clock from '@/components/Icons/Clock'; @@ -17,6 +15,8 @@ import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { data: { @@ -37,7 +37,7 @@ export default function TokenTransfers({ data, txnsCount, error }: Props) { const count = txnsCount?.txns[0]?.count; const txns: TransactionInfo[] = data?.txns; let cursor = data?.cursor; - const { t } = useTranslation(); + const t = useTranslations(); const toggleShowAge = () => setShowAge((s) => !s); const onHandleMouseOver = (e: any, id: string) => { diff --git a/apps/app/src/components/Tokens/NFT/Transfers.tsx b/apps/app/src/components/Tokens/NFT/Transfers.tsx index 8d5044b9..d35b9d2b 100644 --- a/apps/app/src/components/Tokens/NFT/Transfers.tsx +++ b/apps/app/src/components/Tokens/NFT/Transfers.tsx @@ -6,11 +6,11 @@ import Clock from '@/components/Icons/Clock'; import FaInbox from '@/components/Icons/FaInbox'; import FaLongArrowAltRight from '@/components/Icons/FaLongArrowAltRight'; import Skeleton from '@/components/skeleton/common/Skeleton'; +import { Link } from '@/i18n/routing'; import { localFormat } from '@/utils/libs'; import { TransactionInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; import { useState } from 'react'; interface Props { txns: any; @@ -21,8 +21,8 @@ interface Props { } const Transfers = ({ txns, count, cursor, error, tab }: Props) => { - const { t } = useTranslation(); - const errorMessage = t ? t('txns:noTxns') : 'No transactions found!'; + const t = useTranslations(); + const errorMessage = t ? t('noTxns') : 'No transactions found!'; const [showAge, setShowAge] = useState(true); const [address, setAddress] = useState(''); const [page, setPage] = useState(1); diff --git a/apps/app/src/components/Tokens/NFTList.tsx b/apps/app/src/components/Tokens/NFTList.tsx index 4aa64f4b..100f3295 100644 --- a/apps/app/src/components/Tokens/NFTList.tsx +++ b/apps/app/src/components/Tokens/NFTList.tsx @@ -1,16 +1,16 @@ import { Sorting, Token } from '@/utils/types'; import { useEffect, useRef, useState } from 'react'; -import Link from 'next/link'; import { fetcher } from '@/hooks/useFetch'; import { localFormat, serialNumber } from '@/utils/libs'; import { useRouter } from 'next/router'; -import useTranslation from 'next-translate/useTranslation'; import { debounce } from 'lodash'; import TokenImage from '@/components/common/TokenImage'; import SortIcon from '@/components/Icons/SortIcon'; import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; +import { useTranslations } from 'next-intl'; +import { Link, useIntlRouter, usePathname } from '@/i18n/routing'; const initialSorting: Sorting = { sort: 'txns_day', order: 'desc', @@ -31,8 +31,10 @@ interface Props { } const List = ({ data, tokensCount, error }: Props) => { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const { page, search }: any = router.query; const pagination = { page: page ? Number(page) : 1, per_page: 50 }; const [searchResults, setSearchResults] = useState([]); @@ -42,7 +44,7 @@ const List = ({ data, tokensCount, error }: Props) => { const containerRef: any = useRef(null); const [form, setForm] = useState(initialForm); const [sorting, setSorting] = useState(initialSorting); - const errorMessage = t ? t('token:fts.top.empty') : 'No tokens found!'; + const errorMessage = t ? t('fts.top.empty') : 'No tokens found!'; const tokens = data?.tokens; const count = tokensCount?.tokens[0]?.count || 0; @@ -94,9 +96,10 @@ const List = ({ data, tokensCount, error }: Props) => { }; const onFilter = () => { - const { pathname, query } = router; - const { page, ...updatedQuery } = query; - router.push({ pathname, query: { ...updatedQuery, ...form, page: 1 } }); + const { query } = router; + const { page, locale, ...updatedQuery } = query; + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: { ...updatedQuery, ...form, page: 1 } }); }; useEffect(() => { @@ -113,14 +116,16 @@ const List = ({ data, tokensCount, error }: Props) => { if (selectedIndex > -1) { const selectedToken = searchResults[selectedIndex]; if (selectedToken) { - router.push(`/nft-token/${selectedToken.contract}`); + // @ts-ignore: Unreachable code error + intlRouter.push(`/nft-token/${selectedToken.contract}`); } } else { if (value) { onFilter(); setSelectedIndex(-1); } else if (Object.keys(router.query).length > 0) { - router.push(`/nft-tokens`); + // @ts-ignore: Unreachable code error + intlRouter.push(`/nft-tokens`); } } } @@ -146,13 +151,16 @@ const List = ({ data, tokensCount, error }: Props) => { const onOrder = (sortKey: string) => { setSorting((state) => { const { - pathname, - query: { order, ...updatedQuery }, + query: { order, locale, ...updatedQuery }, } = router; const newOrder: 'asc' | 'desc' = (order ?? 'desc') === 'asc' ? 'desc' : 'asc'; const newState: Sorting = { ...state, sort: sortKey, order: newOrder }; - router.push({ pathname, query: { ...updatedQuery, order: newOrder } }); + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname, + query: { ...updatedQuery, order: newOrder }, + }); return newState; }); }; diff --git a/apps/app/src/components/Tokens/NFTTransfers.tsx b/apps/app/src/components/Tokens/NFTTransfers.tsx index f5f49446..941a5aeb 100644 --- a/apps/app/src/components/Tokens/NFTTransfers.tsx +++ b/apps/app/src/components/Tokens/NFTTransfers.tsx @@ -1,8 +1,6 @@ import { TransactionInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; import { useEffect, useState } from 'react'; -import Link from 'next/link'; import { getTimeAgoString, localFormat, nanoToMilli } from '@/utils/libs'; import useRpc from '@/hooks/useRpc'; import TxnStatus from '@/components/common/Status'; @@ -13,6 +11,8 @@ import Clock from '@/components/Icons/Clock'; import Table from '@/components/common/Table'; import ErrorMessage from '@/components/common/ErrorMessage'; import FaInbox from '@/components/Icons/FaInbox'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface ListProps { data: { @@ -32,9 +32,9 @@ interface ListProps { const TransfersList = ({ data, totalCount, error, status }: ListProps) => { const [showAge, setShowAge] = useState(true); const [page, setPage] = useState(1); - const { t } = useTranslation(); + const t = useTranslations(); const { getBlockDetails } = useRpc(); - const errorMessage = t ? t('txns:noTxns') : 'No transactions found!'; + const errorMessage = t ? t('noTxns') : 'No transactions found!'; const [address, setAddress] = useState(''); const [timestamp, setTimeStamp] = useState(''); @@ -57,19 +57,19 @@ const TransfersList = ({ data, totalCount, error, status }: ListProps) => { const res = await getBlockDetails(Number(height)); const resp = res?.header; if (resp) { - setTimeStamp(resp.timestamp_nanosec); + setTimeStamp(resp?.timestamp_nanosec); } } catch (error) { console.error('Error loading schema:', error); } }; - if (typeof status.height === 'string' && Number(status.height) > 0) { - fetchTimeStamp(status.height); + if (typeof status?.height === 'string' && Number(status?.height) > 0) { + fetchTimeStamp(status?.height); } else { - console.log('Invalid height:', status.height); + console.log('Invalid height:', status?.height); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [status.height]); + }, [status?.height]); const toggleShowAge = () => setShowAge((s) => !s); diff --git a/apps/app/src/components/Transactions/Action/AddKey.tsx b/apps/app/src/components/Transactions/Action/AddKey.tsx index c50ac171..8d7f03f9 100644 --- a/apps/app/src/components/Transactions/Action/AddKey.tsx +++ b/apps/app/src/components/Transactions/Action/AddKey.tsx @@ -1,25 +1,25 @@ import FaRight from '@/components/Icons/FaRight'; +import { Link } from '@/i18n/routing'; import { shortenAddress, shortenHex } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; const AddKey = (props: TransactionActionInfo) => { - const { t } = useTranslation(); + const t = useTranslations(); if (typeof props.args.access_key?.permission !== 'object') { return (
- {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)}){' '} - {t ? t('txns:txn.actions.addKey.2') : 'added for'} + {t ? t('txn.actions.addKey.2') : 'added for'} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.4') : 'with permission'} {props.args.access_key?.permission} @@ -31,16 +31,16 @@ const AddKey = (props: TransactionActionInfo) => { return (
- {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)}) - {t ? t('txns:txn.actions.addKey.2') : 'added for'}{' '} + {t ? t('txn.actions.addKey.2') : 'added for'}{' '} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'}{' '} + {t ? t('txn.actions.addKey.4') : 'with permission'}{' '} {props.args.access_key.permission.permission_kind} @@ -51,12 +51,10 @@ const AddKey = (props: TransactionActionInfo) => { return (
- {t ? t('txns:txn.actions.addKey.1') : 'Access key'} ( + {t ? t('txn.actions.addKey.1') : 'Access key'} ( {shortenHex(props.args.public_key)}){' '} - {t ? t('txns:txn.actions.addKey.2') : 'added for'} - - {t ? t('txns:txn.actions.addKey.3') : 'contract'} - + {t ? t('txn.actions.addKey.2') : 'added for'} + {t ? t('txn.actions.addKey.3') : 'contract'} { props.args.access_key.permission.FunctionCall.receiver_id, )} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} - - {t ? t('txns:txn.actions.addKey.5') : 'to call'} - + {t ? t('txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.5') : 'to call'} {props.args.access_key.permission.FunctionCall.method_names.length > 0 ? props.args.access_key.permission.FunctionCall.method_names.join( @@ -76,7 +72,7 @@ const AddKey = (props: TransactionActionInfo) => { ) : 'any'}{' '} - {t ? t('txns:txn.actions.addKey.6') : 'methods'} + {t ? t('txn.actions.addKey.6') : 'methods'}
); }; diff --git a/apps/app/src/components/Transactions/Action/Burrow/Borrow.tsx b/apps/app/src/components/Transactions/Action/Burrow/Borrow.tsx index 182d3f59..be2227f2 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/Borrow.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/Borrow.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const Borrow = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/DecreaseCollateral.tsx b/apps/app/src/components/Transactions/Action/Burrow/DecreaseCollateral.tsx index d40cdd73..5fa7e594 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/DecreaseCollateral.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/DecreaseCollateral.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const DescreaseCollateral = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/Deposit.tsx b/apps/app/src/components/Transactions/Action/Burrow/Deposit.tsx index 15af4067..abe26b59 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/Deposit.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/Deposit.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const Deposit = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/DopositToReserve.tsx b/apps/app/src/components/Transactions/Action/Burrow/DopositToReserve.tsx index 2c330f9d..c830cc90 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/DopositToReserve.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/DopositToReserve.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const DepositToReserve = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/IncreaseCollateral.tsx b/apps/app/src/components/Transactions/Action/Burrow/IncreaseCollateral.tsx index f6b1d4e6..416a52f3 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/IncreaseCollateral.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/IncreaseCollateral.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const IncreaseCollateral = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/Repay.tsx b/apps/app/src/components/Transactions/Action/Burrow/Repay.tsx index b2e9cd9a..d4b4e119 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/Repay.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/Repay.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const Repay = (props: DepositPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Burrow/WithdrawSucceeded.tsx b/apps/app/src/components/Transactions/Action/Burrow/WithdrawSucceeded.tsx index c4705b36..dd9c54f7 100644 --- a/apps/app/src/components/Transactions/Action/Burrow/WithdrawSucceeded.tsx +++ b/apps/app/src/components/Transactions/Action/Burrow/WithdrawSucceeded.tsx @@ -1,7 +1,7 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { DepositPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const WithdrawSucceeded = (props: DepositPropsInfo) => { const log = props.event?.[0]; diff --git a/apps/app/src/components/Transactions/Action/CreateAccount.tsx b/apps/app/src/components/Transactions/Action/CreateAccount.tsx index 98bf4664..17981253 100644 --- a/apps/app/src/components/Transactions/Action/CreateAccount.tsx +++ b/apps/app/src/components/Transactions/Action/CreateAccount.tsx @@ -1,6 +1,6 @@ +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { ActionPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const CreateAccount = (props: ActionPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/DeleteAccount.tsx b/apps/app/src/components/Transactions/Action/DeleteAccount.tsx index b2362188..e123bdf7 100644 --- a/apps/app/src/components/Transactions/Action/DeleteAccount.tsx +++ b/apps/app/src/components/Transactions/Action/DeleteAccount.tsx @@ -1,6 +1,6 @@ +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { ActionPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const DeleteAccount = (props: ActionPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/DeployContract.tsx b/apps/app/src/components/Transactions/Action/DeployContract.tsx index e00d89d2..ad0bb525 100644 --- a/apps/app/src/components/Transactions/Action/DeployContract.tsx +++ b/apps/app/src/components/Transactions/Action/DeployContract.tsx @@ -1,6 +1,6 @@ +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { ActionPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const DeployContract = (props: ActionPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/FunctionCall.tsx b/apps/app/src/components/Transactions/Action/FunctionCall.tsx index 7ea87257..7d0eebc5 100644 --- a/apps/app/src/components/Transactions/Action/FunctionCall.tsx +++ b/apps/app/src/components/Transactions/Action/FunctionCall.tsx @@ -1,7 +1,7 @@ +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { ActionPropsInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import Link from 'next/link'; const FunctionCall = (props: ActionPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Ref/Swap.tsx b/apps/app/src/components/Transactions/Action/Ref/Swap.tsx index 554edeb9..2d66f24a 100644 --- a/apps/app/src/components/Transactions/Action/Ref/Swap.tsx +++ b/apps/app/src/components/Transactions/Action/Ref/Swap.tsx @@ -1,6 +1,6 @@ import TokenInfo from '@/components/common/TokenInfo'; +import { Link } from '@/i18n/routing'; import { EventPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const Swap = (props: EventPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Action/Transfer.tsx b/apps/app/src/components/Transactions/Action/Transfer.tsx index c6c5e199..257a556a 100644 --- a/apps/app/src/components/Transactions/Action/Transfer.tsx +++ b/apps/app/src/components/Transactions/Action/Transfer.tsx @@ -1,6 +1,6 @@ +import { Link } from '@/i18n/routing'; import { shortenAddress, yoctoToNear } from '@/utils/libs'; import { ActionPropsInfo } from '@/utils/types'; -import Link from 'next/link'; const Transfer = (props: ActionPropsInfo) => { const FaRight = (props: { className: string }) => { diff --git a/apps/app/src/components/Transactions/Details.tsx b/apps/app/src/components/Transactions/Details.tsx index 58550d32..8fe9a2f4 100644 --- a/apps/app/src/components/Transactions/Details.tsx +++ b/apps/app/src/components/Transactions/Details.tsx @@ -31,12 +31,10 @@ import { TransactionLog, } from '@/utils/types'; import Big from 'big.js'; -import Link from 'next/link'; import { useEffect, useMemo, useState } from 'react'; import ArrowDown from '../Icons/ArrowDown'; import ArrowUp from '../Icons/ArrowUp'; import Question from '../Icons/Question'; -import useTranslation from 'next-translate/useTranslation'; import TxnStatus from '../common/Status'; import FaRight from '../Icons/FaRight'; import { Tooltip } from '@reach/tooltip'; @@ -45,6 +43,8 @@ import EventLogs from './Action'; import Actions from './Actions'; import TokenImage, { NFTImage } from '../common/TokenImage'; import { isEmpty } from 'lodash'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { loading: boolean; @@ -58,7 +58,7 @@ interface Props { const Details = (props: Props) => { const { loading, txn, rpcTxn, statsData, price, isContract = false } = props; const [more, setMore] = useState(false); - const { t } = useTranslation(); + const t = useTranslations(); const { fts, nfts } = useMemo(() => { function tokensTransfers(receipts: InventoryInfo[]) { let fts: FtsInfo[] = []; @@ -169,23 +169,21 @@ const Details = (props: Props) => {
{networkId === 'testnet' && (
- {t - ? t('txns:testnetNotice') - : '[ This is a Testnet transaction only ]'} + {t ? t('testnetNotice') : '[ This is a Testnet transaction only ]'}
)}
- {t ? t('txns:txn.hash.text.0') : 'Txn Hash'} + {t ? t('txn.hash.text.0') : 'Txn Hash'}
{!txn?.transaction_hash ? (
@@ -200,7 +198,7 @@ const Details = (props: Props) => {
@@ -209,7 +207,7 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.status.text.0') : 'Status'} + {t ? t('txn.status.text.0') : 'Status'}
{loading ? (
@@ -235,14 +233,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.block.text.0') : 'Block Height'} + {t ? t('txn.block.text.0') : 'Block Height'}
{!txn?.included_in_block_hash ? (
@@ -266,14 +264,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.timestamp.text.0') : 'Timestamp'} + {t ? t('txn.timestamp.text.0') : 'Timestamp'}
{!txn?.block_timestamp ? (
@@ -322,14 +320,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.from.text.0') : 'From'} + {t ? t('txn.from.text.0') : 'From'}
{!txn?.signer_account_id ? (
@@ -349,7 +347,7 @@ const Details = (props: Props) => {
@@ -359,7 +357,7 @@ const Details = (props: Props) => { {isContract ? 'Interacted With (To)' : t - ? t('txns:txn.to.text.0') + ? t('txn.to.text.0') : 'To'}
{!txn?.receiver_account_id ? ( @@ -643,14 +641,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.deposit.text.0') : 'Deposit Value'} + {t ? t('txn.deposit.text.0') : 'Deposit Value'}
{loading ? (
@@ -659,7 +657,7 @@ const Details = (props: Props) => { ) : (
@@ -681,14 +679,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.fee.text.0') : 'Transaction fee'} + {t ? t('txn.fee.text.0') : 'Transaction fee'}
{!txn?.outcomes_agg?.transaction_fee ? (
@@ -714,14 +712,14 @@ const Details = (props: Props) => {
- {t ? t('txns:txn.price.text.0') : 'Ⓝ Price'} + {t ? t('txn.price.text.0') : 'Ⓝ Price'}
{loading ? (
@@ -781,14 +779,14 @@ const Details = (props: Props) => {
- {t('txns:txn.gas.text.0')} + {t('txn.gas.text.0')}
{!txn?.outcomes_agg?.gas_used ? (
@@ -811,14 +809,14 @@ const Details = (props: Props) => {
- {t('txns:txn.burnt.text.0')} + {t('txn.burnt.text.0')}
{!txn?.receipt_conversion_tokens_burnt || !txn?.receipt_conversion_gas_burnt ? ( diff --git a/apps/app/src/components/Transactions/Latest.tsx b/apps/app/src/components/Transactions/Latest.tsx index 49e520b5..8b4f2540 100644 --- a/apps/app/src/components/Transactions/Latest.tsx +++ b/apps/app/src/components/Transactions/Latest.tsx @@ -1,8 +1,6 @@ import React from 'react'; -import Link from 'next/link'; import 'react-perfect-scrollbar/dist/css/styles.css'; import PerfectScrollbar from 'react-perfect-scrollbar'; -import useTranslation from 'next-translate/useTranslation'; import Skeleton from '../skeleton/common/Skeleton'; import { TransactionInfo } from '@/utils/types'; import { @@ -13,6 +11,8 @@ import { yoctoToNear, } from '@/utils/libs'; import { Tooltip } from '@reach/tooltip'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { txns: TransactionInfo[]; @@ -20,7 +20,7 @@ interface Props { } const LatestTransactions = ({ txns, error }: Props) => { - const { t } = useTranslation(); + const t = useTranslations(); return ( <> @@ -28,12 +28,12 @@ const LatestTransactions = ({ txns, error }: Props) => { {!txns && error && (
- {t ? t('home:error') : ' Error!'} + {t ? t('error') : ' Error!'}
)} {!error && txns?.length === 0 && (
- {t ? t('home:noTxns') : ' No transactions found!'} + {t ? t('noTxns') : ' No transactions found!'}
)} {error && txns?.length === 0 && ( @@ -92,7 +92,7 @@ const LatestTransactions = ({ txns, error }: Props) => { TX
-
+
{
- {t ? t('home:txnFrom') : 'From'}{' '} + {t ? t('txnFrom') : 'From'}{' '} {
- {t ? t('home:txnTo') : 'To'}{' '} + {t ? t('txnTo') : 'To'}{' '} { - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const intlRouter = useIntlRouter(); + const pathname = usePathname(); const [showAge, setShowAge] = useState(true); const [address, setAddress] = useState(''); const [form, setForm] = useState(initialForm); const [page, setPage] = useState(1); - const errorMessage = t ? t('txns:noTxns') : ' No transactions found!'; + const errorMessage = t ? t('noTxns') : ' No transactions found!'; const count = txnsCount?.txns[0]?.count; const txns = txnsData?.txns; @@ -75,8 +77,8 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { setPage(1); const { action, method, from, to } = form; - const { pathname, query } = router; - const { cursor, p, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, locale, ...updatedQuery } = query; const queryParams = { ...(action && { action }), @@ -87,21 +89,23 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { const finalQuery = { ...updatedQuery, ...queryParams }; - router.push({ pathname, query: finalQuery }); + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname, query: finalQuery }); }; const onClear = (e: React.MouseEvent) => { const { name } = e.currentTarget; setPage(1); - const { cursor, p, ...restQuery } = router.query; + const { cursor, p, locale, ...restQuery } = router.query; if (name === 'type') { setForm((prev) => ({ ...prev, action: '', method: '' })); - const { action, method, ...newQuery } = restQuery; + const { action, method, locale, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); return; @@ -109,8 +113,9 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { setForm((f) => ({ ...f, [name]: '' })); const { [name]: _, ...newQuery } = restQuery; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); } @@ -121,21 +126,34 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { const onAllClear = () => { setForm(initialForm); - const { cursor, action, method, from, to, block, order, p, ...newQuery } = - router.query; + const { + cursor, + action, + method, + from, + to, + block, + order, + p, + locale, + ...newQuery + } = router.query; - router.push({ - pathname: router.pathname, + // @ts-ignore: Unreachable code error + intlRouter.push({ + pathname: pathname, query: newQuery, }); }; const onOrder = () => { - const { pathname, query } = router; - const { cursor, p, order, ...updatedQuery } = query; + const { query } = router; + const { cursor, p, order, locale, ...updatedQuery } = query; const currentOrder = order ?? 'desc'; const newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; - router.push({ + + // @ts-ignore: Unreachable code error + intlRouter.push({ pathname: pathname, query: { ...updatedQuery, @@ -155,7 +173,8 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { function removeCursor() { const queryParams = router.query; - const { cursor, order, p, keyword, query, filter, ...rest } = queryParams; + const { cursor, order, p, locale, keyword, query, filter, ...rest } = + queryParams; return rest; } @@ -174,7 +193,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { 'pl-4 py-3 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10 w-12', }, { - header: {t ? t('txns:hash') : 'TXN HASH'}, + header: {t ? t('hash') : 'TXN HASH'}, key: 'transaction_hash', cell: (row: TransactionInfo) => ( @@ -202,7 +221,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { header: ( - {t ? t('txns:type') : 'METHOD'} + {t ? t('type') : 'METHOD'} @@ -220,7 +239,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 dark:bg-green-250 h-7 text-white dark:text-black text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -255,7 +274,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { thClassName: 'px-1.5', }, { - header: {t ? t('txns:depositValue') : 'DEPOSIT VALUE'}, + header: {t ? t('depositValue') : 'DEPOSIT VALUE'}, key: 'deposit', cell: (row: TransactionInfo) => ( @@ -271,7 +290,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { 'px-4 py-4 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', }, { - header: {t ? t('txns:txnFee') : 'TXN FEE'}, + header: {t ? t('txnFee') : 'TXN FEE'}, key: 'transaction_fee', cell: (row: TransactionInfo) => ( @@ -290,7 +309,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { header: ( - {t ? t('txns:from') : 'FROM'} + {t ? t('from') : 'FROM'} @@ -300,9 +319,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { value={form.from} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -312,7 +329,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 dark:bg-green-250 dark:text-black h-7 text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -372,7 +389,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { header: ( - {t ? t('txns:to') : 'To'} + {t ? t('to') : 'To'} @@ -382,9 +399,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { value={form.to} onChange={onChange} placeholder={ - t - ? t('txns:filter.placeholder') - : 'Search by address e.g. Ⓝ..' + t ? t('filter.placeholder') : 'Search by address e.g. Ⓝ..' } className="border dark:border-black-200 rounded h-8 mb-2 px-2 text-nearblue-600 dark:text-neargray-10 text-xs" /> @@ -394,7 +409,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { className="flex items-center justify-center flex-1 rounded bg-green-500 dark:bg-green-250 h-7 dark:text-black text-white text-xs mr-2" > {' '} - {t ? t('txns:filter.filter') : 'Filter'} + {t ? t('filter.filter') : 'Filter'}
@@ -439,7 +454,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { 'px-4 py-3 text-sm text-nearblue-600 dark:text-neargray-10 font-medium w-48', }, { - header: {t ? t('txns:blockHeight') : ' BLOCK HEIGHT'}, + header: {t ? t('blockHeight') : ' BLOCK HEIGHT'}, key: 'block_height', cell: (row: TransactionInfo) => ( @@ -476,10 +491,10 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { > {showAge ? t - ? t('txns:age') + ? t('age') : 'AGE' : t - ? t('txns:ageDT') + ? t('ageDT') : 'DATE TIME (UTC)'} {showAge && ( @@ -517,7 +532,7 @@ const List = ({ txnsData, txnsCount, error }: ListProps) => { txns?.length > 0 && `${ t - ? t('txns:listing', { + ? t('listing', { count: localFormat ? localFormat(count.toString()) : '', }) : `More than > ${count} transactions found` diff --git a/apps/app/src/components/Transactions/Overview.tsx b/apps/app/src/components/Transactions/Overview.tsx index b111a5bf..7caeb0d7 100644 --- a/apps/app/src/components/Transactions/Overview.tsx +++ b/apps/app/src/components/Transactions/Overview.tsx @@ -9,11 +9,11 @@ import { gasPrice } from '@/utils/near'; import { useEffect, useMemo, useState } from 'react'; import { ChartConfigType, ChartInfo, StatusInfo } from '@/utils/types'; import { networkId } from '@/utils/config'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; import { useTheme } from 'next-themes'; import { Tooltip } from '@reach/tooltip'; import Image from 'next/image'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { stats: StatusInfo; @@ -22,7 +22,7 @@ interface Props { } const Overview = ({ stats, chartsDetails, error }: Props) => { - const { t } = useTranslation(); + const t = useTranslations(); const { theme } = useTheme(); const [chartConfig, setChartConfig] = useState(null); @@ -194,14 +194,14 @@ const Overview = ({ stats, chartsDetails, error }: Props) => { ? 'near price_dark.svg' : 'near price.svg' }`} - alt={t ? t('home:nearPrice') : 'nearPrice'} + alt={t ? t('nearPrice') : 'nearPrice'} width={24} height={24} />

- {t ? t('home:nearPrice') : 'NEAR PRICE'} + {t ? t('nearPrice') : 'NEAR PRICE'}

{error ? ( @@ -246,14 +246,14 @@ const Overview = ({ stats, chartsDetails, error }: Props) => { src={`/images/${ theme === 'dark' ? 'market_dark.svg' : 'market.svg' }`} - alt={t ? t('home:marketCap') : 'marketCap'} + alt={t ? t('marketCap') : 'marketCap'} width={24} height={24} />

- {t ? t('home:marketCap') : ' MARKET CAP'} + {t ? t('marketCap') : ' MARKET CAP'}

{error ? ( @@ -284,14 +284,14 @@ const Overview = ({ stats, chartsDetails, error }: Props) => { ? 'transactions_dark.svg' : 'transactions.svg' }`} - alt={t ? t('home:transactions') : 'transactions'} + alt={t ? t('transactions') : 'transactions'} width={24} height={24} />

- {t ? t('home:transactions') : 'TRANSACTIONS'} + {t ? t('transactions') : 'TRANSACTIONS'}

{error ? ( @@ -322,7 +322,7 @@ const Overview = ({ stats, chartsDetails, error }: Props) => {

{' '} - {t ? t('home:gasPrice') : 'GAS PRICE'} + {t ? t('gasPrice') : 'GAS PRICE'}

{error ? ( @@ -342,7 +342,7 @@ const Overview = ({ stats, chartsDetails, error }: Props) => { src={`/images/${ (theme === 'dark' && 'pickaxe_dark.svg') || 'pickaxe.svg' }`} - alt={t ? t('home:activeValidator') : 'activeValidator'} + alt={t ? t('activeValidator') : 'activeValidator'} width={24} height={24} /> @@ -351,7 +351,7 @@ const Overview = ({ stats, chartsDetails, error }: Props) => {

{' '} - {t ? t('home:activeValidator') : 'ACTIVE VALIDATORS'}{' '} + {t ? t('activeValidator') : 'ACTIVE VALIDATORS'}{' '}

{error ? ( @@ -370,7 +370,7 @@ const Overview = ({ stats, chartsDetails, error }: Props) => {

- {t ? t('home:avgBlockTime') : 'AVG. BLOCK TIME'} + {t ? t('avgBlockTime') : 'AVG. BLOCK TIME'}

{error ? ( @@ -395,7 +395,7 @@ const Overview = ({ stats, chartsDetails, error }: Props) => { {chartConfig && (

{t - ? t('home:transactionHistory', { days: 14 }) + ? t('transactionHistory', { days: 14 }) : 'NEAR TRANSACTION HISTORY IN 14 DAYS'}

)} diff --git a/apps/app/src/components/Transactions/ReceiptSummary.tsx b/apps/app/src/components/Transactions/ReceiptSummary.tsx index 25904da1..14570376 100644 --- a/apps/app/src/components/Transactions/ReceiptSummary.tsx +++ b/apps/app/src/components/Transactions/ReceiptSummary.tsx @@ -3,11 +3,11 @@ import { RPCTransactionInfo, TransactionInfo } from '@/utils/types'; import { isEmpty } from 'lodash'; import { useEffect, useState } from 'react'; import FaHourglassStart from '../Icons/FaHourglassStart'; -import useTranslation from 'next-translate/useTranslation'; import Skeleton from '../skeleton/common/Skeleton'; import ErrorMessage from '../common/ErrorMessage'; import FaInbox from '../Icons/FaInbox'; import ReceiptSummaryRow from './Receipts/ReceiptSummaryRow'; +import { useTranslations } from 'next-intl'; interface Props { txn: TransactionInfo; @@ -22,7 +22,7 @@ interface Props { const ReceiptSummary = (props: Props) => { const { rpcTxn, txn, loading, statsData } = props; - const { t } = useTranslation(); + const t = useTranslations(); const [receipt, setReceipt] = useState(null); function transactionReceipts(txn: RPCTransactionInfo) { const actions: any = @@ -139,7 +139,7 @@ const ReceiptSummary = (props: Props) => { scope="col" className="px-4 py-4 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase whitespace-nowrap tracking-wider" > - {t ? t('txns:txn.receipts.from.text.0') : 'From'} + {t ? t('txn.receipts.from.text.0') : 'From'} { scope="col" className="px-4 py-4 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase whitespace-nowrap tracking-wider" > - {t ? t('txns:txn.receipts.to.text.0') : 'To'} + {t ? t('txn.receipts.to.text.0') : 'To'} { - const { t } = useTranslation(); + const t = useTranslations(); if (typeof props.args.access_key?.permission !== 'object') { return (
{' '} - {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)}){' '} - {t ? t('txns:txn.actions.addKey.2') : 'added for'} + {t ? t('txn.actions.addKey.2') : 'added for'} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.4') : 'with permission'} {props.args.access_key?.permission} @@ -31,16 +31,16 @@ const AddKey = (props: TransactionActionInfo) => { return (
{' '} - {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)}) - {t ? t('txns:txn.actions.addKey.2') : 'added for'}{' '} + {t ? t('txn.actions.addKey.2') : 'added for'}{' '} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'}{' '} + {t ? t('txn.actions.addKey.4') : 'with permission'}{' '} {props.args.access_key.permission.permission_kind} @@ -51,12 +51,10 @@ const AddKey = (props: TransactionActionInfo) => { return (
{' '} - {t ? t('txns:txn.actions.addKey.1') : 'Access key'} ( + {t ? t('txn.actions.addKey.1') : 'Access key'} ( {shortenHex(props.args.public_key)}){' '} - {t ? t('txns:txn.actions.addKey.2') : 'added for'} - - {t ? t('txns:txn.actions.addKey.3') : 'contract'} - + {t ? t('txn.actions.addKey.2') : 'added for'} + {t ? t('txn.actions.addKey.3') : 'contract'} { props.args.access_key.permission.FunctionCall.receiver_id, )} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} - - {t ? t('txns:txn.actions.addKey.5') : 'to call'} - + {t ? t('txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.5') : 'to call'} {props.args.access_key.permission.FunctionCall.method_names.length > 0 ? props.args.access_key.permission.FunctionCall.method_names.join( @@ -76,7 +72,7 @@ const AddKey = (props: TransactionActionInfo) => { ) : 'any'}{' '} - {t ? t('txns:txn.actions.addKey.6') : 'methods'} + {t ? t('txn.actions.addKey.6') : 'methods'}
); }; diff --git a/apps/app/src/components/Transactions/Receipts/Action/CreateAccount.tsx b/apps/app/src/components/Transactions/Receipts/Action/CreateAccount.tsx index 1e8381d8..db41c218 100644 --- a/apps/app/src/components/Transactions/Receipts/Action/CreateAccount.tsx +++ b/apps/app/src/components/Transactions/Receipts/Action/CreateAccount.tsx @@ -1,21 +1,21 @@ import FaUser from '@/components/Icons/FaUser'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; const CreateAccount = (props: any) => { - const { t } = useTranslation(); + const t = useTranslations(); return (
{' '} - {t ? t('txns:txn.actions.createAccount.0') : 'New account'} ( + {t ? t('txn.actions.createAccount.0') : 'New account'} ( {shortenAddress(props.receiver)} - ) {t ? t('txns:txn.actions.createAccount.1') : 'created'} + ) {t ? t('txn.actions.createAccount.1') : 'created'}
); }; diff --git a/apps/app/src/components/Transactions/Receipts/Action/DeleteAccount.tsx b/apps/app/src/components/Transactions/Receipts/Action/DeleteAccount.tsx index 877ed21c..94d7e2fe 100644 --- a/apps/app/src/components/Transactions/Receipts/Action/DeleteAccount.tsx +++ b/apps/app/src/components/Transactions/Receipts/Action/DeleteAccount.tsx @@ -1,15 +1,15 @@ import FaUser from '@/components/Icons/FaUser'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; const DeleteAccount = (props: TransactionActionInfo) => { - const { t } = useTranslation(); + const t = useTranslations(); return (
- {t ? t('txns:txn.actions.deleteAccount.0') : 'Delete account'} ( + {t ? t('txn.actions.deleteAccount.0') : 'Delete account'} ( { {shortenAddress(props.receiver)} ){' '} - {t - ? t('txns:txn.actions.deleteAccount.1') - : 'and transfer remaining funds to'} + {t ? t('txn.actions.deleteAccount.1') : 'and transfer remaining funds to'} { - const { t } = useTranslation(); + const t = useTranslations(); const { args } = props; return (
{' '} - {t ? t('txns:txn.actions.deleteKey.0') : 'Key'} ( + {t ? t('txn.actions.deleteKey.0') : 'Key'} ( {shortenHex(args.public_key)}){' '} - {t ? t('txns:txn.actions.deleteKey.1') : 'deleted'} + {t ? t('txn.actions.deleteKey.1') : 'deleted'}
); }; diff --git a/apps/app/src/components/Transactions/Receipts/Action/DeployContract.tsx b/apps/app/src/components/Transactions/Receipts/Action/DeployContract.tsx index 9d8b37c2..2559a37c 100644 --- a/apps/app/src/components/Transactions/Receipts/Action/DeployContract.tsx +++ b/apps/app/src/components/Transactions/Receipts/Action/DeployContract.tsx @@ -1,24 +1,24 @@ import FaCode from '@/components/Icons/FaCode'; +import { Link } from '@/i18n/routing'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; const DeployContract = (props: TransactionActionInfo) => { - const { t } = useTranslation(); + const t = useTranslations(); const { receiver } = props; return (
{' '} - {t ? t('txns:txn.actions.deployContract.0') : 'Contract'} ( + {t ? t('txn.actions.deployContract.0') : 'Contract'} ( {shortenAddress(receiver)} - ) {t ? t('txns:txn.actions.deployContract.1') : 'deployed'} + ) {t ? t('txn.actions.deployContract.1') : 'deployed'}
); }; diff --git a/apps/app/src/components/Transactions/Receipts/Action/FunctionCall.tsx b/apps/app/src/components/Transactions/Receipts/Action/FunctionCall.tsx index 4a59de1e..8418dfd4 100644 --- a/apps/app/src/components/Transactions/Receipts/Action/FunctionCall.tsx +++ b/apps/app/src/components/Transactions/Receipts/Action/FunctionCall.tsx @@ -3,11 +3,11 @@ import { hexy } from '@/utils/hexy'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; import RlpTransaction from '../RlpTransaction'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const FunctionCall = (props: TransactionActionInfo) => { - const { t } = useTranslation(); + const t = useTranslations(); const { args, receiver } = props; function displayArgs(args: any) { @@ -37,9 +37,9 @@ const FunctionCall = (props: TransactionActionInfo) => { return (
- {t ? t('txns:txn.actions.functionCall.0') : 'Called method'} + {t ? t('txn.actions.functionCall.0') : 'Called method'} {args?.method_name}{' '} - {t ? t('txns:txn.actions.functionCall.1') : 'in contract'} + {t ? t('txn.actions.functionCall.1') : 'in contract'} { - const { t } = useTranslation(); + const t = useTranslations(); const { args } = props; return (
- {t ? t('txns:txn.actions.stake.0') : 'Staked'} + {t ? t('txn.actions.stake.0') : 'Staked'} {args.stake ? yoctoToNear(args.stake, true) : args.stake ?? ''}Ⓝ {' '} - {t ? t('txns:txn.actions.stake.1') : 'with'} {shortenHex(args.public_key)} + {t ? t('txn.actions.stake.1') : 'with'} {shortenHex(args.public_key)}
); }; diff --git a/apps/app/src/components/Transactions/Receipts/Action/Transfer.tsx b/apps/app/src/components/Transactions/Receipts/Action/Transfer.tsx index db682751..4cedc78d 100644 --- a/apps/app/src/components/Transactions/Receipts/Action/Transfer.tsx +++ b/apps/app/src/components/Transactions/Receipts/Action/Transfer.tsx @@ -1,22 +1,22 @@ import FaArrowAltCircleRight from '@/components/Icons/FaArrowAltCircleRight'; +import { Link } from '@/i18n/routing'; import { shortenAddress, yoctoToNear } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; const Transfer = (props: TransactionActionInfo) => { - const { t } = useTranslation(); + const t = useTranslations(); const { args, receiver } = props; return (
{' '} - {t ? t('txns:txn.actions.transfer.0') : 'Transferred'} + {t ? t('txn.actions.transfer.0') : 'Transferred'} {args.deposit ? yoctoToNear(args.deposit, true) : args.deposit ?? ''} Ⓝ {' '} - {t ? t('txns:txn.actions.transfer.1') : 'to'} + {t ? t('txn.actions.transfer.1') : 'to'} { const hashes = ['output', 'inspect']; const [pageHash, setHash] = useState('output'); const [tabIndex, setTabIndex] = useState(0); - const { t } = useTranslation(); + const t = useTranslations(); const onTab = (index: number) => { setHash(hashes[index]); }; @@ -278,7 +278,7 @@ const ReceiptInfo = ({ receipt }: Props) => {
@@ -287,7 +287,7 @@ const ReceiptInfo = ({ receipt }: Props) => {
- {t ? t('txns:txn.status.text.0') : 'Status'} + {t ? t('txn.status.text.0') : 'Status'} {receipt?.outcome?.status !== undefined && ( diff --git a/apps/app/src/components/Transactions/Receipts/ReceiptKind.tsx b/apps/app/src/components/Transactions/Receipts/ReceiptKind.tsx index 3fee602c..4a54e923 100644 --- a/apps/app/src/components/Transactions/Receipts/ReceiptKind.tsx +++ b/apps/app/src/components/Transactions/Receipts/ReceiptKind.tsx @@ -2,8 +2,8 @@ import { hexy } from '@/utils/hexy'; import { yoctoToNear } from '@/utils/libs'; import { ReceiptKindInfo } from '@/utils/types'; import RlpTransaction from './RlpTransaction'; -import useTranslation from 'next-translate/useTranslation'; import FaTimesCircle from '@/components/Icons/FaTimesCircle'; +import { useTranslations } from 'next-intl'; const backgroundColorClasses: Record = { transfer: 'bg-green-50 dark:bg-green-200', @@ -19,7 +19,7 @@ const backgroundColorClasses: Record = { const ReceiptKind = (props: ReceiptKindInfo) => { const { action, onClick, isTxTypeActive, receiver, receipt } = props; - const { t } = useTranslation(); + const t = useTranslations(); const args = action?.args?.args; const modifiedData = action?.args?.methodName === 'submit' && receiver.includes('aurora') @@ -66,7 +66,7 @@ const ReceiptKind = (props: ReceiptKindInfo) => { > {action?.kind !== 'functionCall' && action?.kind !== 'delegateAction' && - t(`txns:${action?.kind}`)} + t(`${action?.kind}`)} {action?.kind === 'delegateAction' ? (
{`Delegate`}
) : null} diff --git a/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx b/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx index 8604ae4e..3e956d11 100644 --- a/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx +++ b/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx @@ -2,14 +2,14 @@ import Question from '@/components/Icons/Question'; import { convertToMetricPrefix, localFormat, yoctoToNear } from '@/utils/libs'; import { ReceiptsPropsInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; -import useTranslation from 'next-translate/useTranslation'; -import Link from 'next/link'; import TransactionActions from './TransactionActions'; import ReceiptStatus from './ReceiptStatus'; import { useEffect, useRef, useState } from 'react'; import useRpc from '@/hooks/useRpc'; import TxnsReceiptStatus from '@/components/common/TxnsReceiptStatus'; import useHash from '@/hooks/useHash'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; interface Props { receipt: ReceiptsPropsInfo | any; @@ -19,7 +19,7 @@ interface Props { const ReceiptRow = (props: Props) => { const { receipt, borderFlag, loading } = props; - const { t } = useTranslation(); + const t = useTranslations(); const [block, setBlock] = useState<{ height: string } | null>(null); const { getBlockDetails } = useRpc(); const [pageHash] = useHash(); @@ -97,14 +97,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.receipt.text.0') : 'Receipt'} + {t ? t('txn.receipts.receipt.text.0') : 'Receipt'}
{!receipt || loading ? (
@@ -119,7 +119,7 @@ const ReceiptRow = (props: Props) => {
@@ -128,7 +128,7 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.status.text.0') : 'Status'} + {t ? t('txn.status.text.0') : 'Status'}
{!receipt || loading ? (
@@ -152,7 +152,7 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.block.text.0') : 'Block'} + {t ? t('txn.receipts.block.text.0') : 'Block'}
{!block?.height || loading ? (
@@ -175,14 +175,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.from.text.0') : 'From'} + {t ? t('txn.receipts.from.text.0') : 'From'}
{!receipt || loading ? (
@@ -204,14 +204,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.to.text.0') : 'To'} + {t ? t('txn.receipts.to.text.0') : 'To'}
{!receipt || loading ? (
@@ -234,7 +234,7 @@ const ReceiptRow = (props: Props) => {
@@ -242,7 +242,7 @@ const ReceiptRow = (props: Props) => {
{t - ? t('txns:txn.receipts.burnt.text.0') + ? t('txn.receipts.burnt.text.0') : 'Burnt Gas & Tokens by Receipt'}
{!receipt || loading ? ( @@ -270,14 +270,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.actions.text.0') : 'Actions'} + {t ? t('txn.receipts.actions.text.0') : 'Actions'}
{!receipt || loading ? (
@@ -304,14 +304,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.result.text.0') : 'Result'} + {t ? t('txn.receipts.result.text.0') : 'Result'}
{!receipt || loading ? (
@@ -328,14 +328,14 @@ const ReceiptRow = (props: Props) => {
- {t ? t('txns:txn.receipts.logs.text.0') : 'Logs'} + {t ? t('txn.receipts.logs.text.0') : 'Logs'}
{!receipt || loading ? (
diff --git a/apps/app/src/components/Transactions/Receipts/ReceiptSummaryRow.tsx b/apps/app/src/components/Transactions/Receipts/ReceiptSummaryRow.tsx index 06417bea..d473165b 100644 --- a/apps/app/src/components/Transactions/Receipts/ReceiptSummaryRow.tsx +++ b/apps/app/src/components/Transactions/Receipts/ReceiptSummaryRow.tsx @@ -8,10 +8,10 @@ import { TransactionInfo, } from '@/utils/types'; import Big from 'big.js'; -import Link from 'next/link'; import { Fragment } from 'react'; import TxnsReceiptStatus from '@/components/common/TxnsReceiptStatus'; import { Tooltip } from '@reach/tooltip'; +import { Link } from '@/i18n/routing'; interface Props { txn: TransactionInfo; diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/AddKey.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/AddKey.tsx index 64b52242..e461597f 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/AddKey.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/AddKey.tsx @@ -1,29 +1,29 @@ import FaKey from '@/components/Icons/FaKey'; import { shortenAddress, shortenHex } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const AddKey = (props: TransactionActionInfo) => { const { action } = props; - const { t } = useTranslation(); + const t = useTranslations(); if (typeof props.args.access_key?.permission !== 'object') { return ( <>
{' '} - {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)} - ) {t ? t('txns:txn.actions.addKey.2') : 'added for'} + ) {t ? t('txn.actions.addKey.2') : 'added for'} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.4') : 'with permission'} {props.args.access_key?.permission} @@ -40,16 +40,16 @@ const AddKey = (props: TransactionActionInfo) => { <>
{' '} - {t ? t('txns:txn.actions.addKey.0') : 'New key'} ( + {t ? t('txn.actions.addKey.0') : 'New key'} ( {shortenHex(props.args.public_key)} - ){t ? t('txns:txn.actions.addKey.2') : 'added for'}{' '} + ){t ? t('txn.actions.addKey.2') : 'added for'}{' '} {shortenAddress(props.receiver)} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'}{' '} + {t ? t('txn.actions.addKey.4') : 'with permission'}{' '} {props.args.access_key.permission.permission_kind} @@ -65,10 +65,10 @@ const AddKey = (props: TransactionActionInfo) => { <>
{' '} - {t ? t('txns:txn.actions.addKey.1') : 'Access key'} ( + {t ? t('txn.actions.addKey.1') : 'Access key'} ( {shortenHex(props.args.public_key)}){' '} - {t ? t('txns:txn.actions.addKey.2') : 'added for'} - {t ? t('txns:txn.actions.addKey.3') : 'contract'} + {t ? t('txn.actions.addKey.2') : 'added for'} + {t ? t('txn.actions.addKey.3') : 'contract'} { props.args.access_key.permission.FunctionCall.receiver_id, )} - {t ? t('txns:txn.actions.addKey.4') : 'with permission'} - {t ? t('txns:txn.actions.addKey.5') : 'to call'} + {t ? t('txn.actions.addKey.4') : 'with permission'} + {t ? t('txn.actions.addKey.5') : 'to call'} {props.args.access_key.permission.FunctionCall.method_names.length > 0 ? props.args.access_key.permission.FunctionCall.method_names.join( @@ -86,7 +86,7 @@ const AddKey = (props: TransactionActionInfo) => { ) : 'any'}{' '} - {t ? t('txns:txn.actions.addKey.6') : 'methods'} + {t ? t('txn.actions.addKey.6') : 'methods'}
diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/CreateAccount.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/CreateAccount.tsx index 6f483786..20783489 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/CreateAccount.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/CreateAccount.tsx @@ -1,26 +1,26 @@ import FaUser from '@/components/Icons/FaUser'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const CreateAccount = (props: TransactionActionInfo) => { const { action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
{' '} - {t ? t('txns:txn.actions.createAccount.0') : 'New account'} ( + {t ? t('txn.actions.createAccount.0') : 'New account'} ( {shortenAddress(props.receiver)} - ) {t ? t('txns:txn.actions.createAccount.1') : 'created'} + ) {t ? t('txn.actions.createAccount.1') : 'created'}
diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/DeleteAccount.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/DeleteAccount.tsx index 55cdba86..f7111968 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/DeleteAccount.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/DeleteAccount.tsx @@ -1,19 +1,19 @@ import FaUser from '@/components/Icons/FaUser'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const DeleteAccount = (props: TransactionActionInfo) => { const { action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
- {t ? t('txns:txn.actions.deleteAccount.0') : 'Delete account'} ( + {t ? t('txn.actions.deleteAccount.0') : 'Delete account'} ( { ){' '} {t - ? t('txns:txn.actions.deleteAccount.1') + ? t('txn.actions.deleteAccount.1') : 'and transfer remaining funds to'} { const { args, action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
{' '} - {t ? t('txns:txn.actions.deleteKey.0') : 'Key'} ( + {t ? t('txn.actions.deleteKey.0') : 'Key'} ( {shortenHex(args.public_key)}){' '} - {t ? t('txns:txn.actions.deleteKey.1') : 'deleted'} + {t ? t('txn.actions.deleteKey.1') : 'deleted'}
diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/DeployContract.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/DeployContract.tsx index a9a16f0b..69d5c0de 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/DeployContract.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/DeployContract.tsx @@ -1,26 +1,26 @@ import FaCode from '@/components/Icons/FaCode'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const DeployContract = (props: TransactionActionInfo) => { const { receiver, action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
{' '} - {t ? t('txns:txn.actions.deployContract.0') : 'Contract'} ( + {t ? t('txn.actions.deployContract.0') : 'Contract'} ( {shortenAddress(receiver)} - ) {t ? t('txns:txn.actions.deployContract.1') : 'deployed'} + ) {t ? t('txn.actions.deployContract.1') : 'deployed'}
diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/FunctionCall.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/FunctionCall.tsx index 7d01d389..1382d2cf 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/FunctionCall.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/FunctionCall.tsx @@ -2,13 +2,13 @@ import FaCode from '@/components/Icons/FaCode'; import { hexy } from '@/utils/hexy'; import { shortenAddress } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const FunctionCall = (props: TransactionActionInfo) => { const { args, receiver, action } = props; - const { t } = useTranslation(); + const t = useTranslations(); function displayArgs(args: any) { if (!args || typeof args === 'undefined') return 'The arguments are empty'; @@ -49,9 +49,9 @@ const FunctionCall = (props: TransactionActionInfo) => { <>
- {t ? t('txns:txn.actions.functionCall.0') : 'Called method'} + {t ? t('txn.actions.functionCall.0') : 'Called method'} {args?.method_name}{' '} - {t ? t('txns:txn.actions.functionCall.1') : 'in contract'} + {t ? t('txn.actions.functionCall.1') : 'in contract'} { const { args, action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
- {t ? t('txns:txn.actions.stake.0') : 'Staked'} + {t ? t('txn.actions.stake.0') : 'Staked'} {args.stake ? yoctoToNear(args.stake, true) : args.stake ?? ''}Ⓝ {' '} - {t ? t('txns:txn.actions.stake.1') : 'with'}{' '} - {shortenHex(args.public_key)} + {t ? t('txn.actions.stake.1') : 'with'} {shortenHex(args.public_key)}
diff --git a/apps/app/src/components/Transactions/TreeReceipts/Action/Transfer.tsx b/apps/app/src/components/Transactions/TreeReceipts/Action/Transfer.tsx index c1e83304..d304660d 100644 --- a/apps/app/src/components/Transactions/TreeReceipts/Action/Transfer.tsx +++ b/apps/app/src/components/Transactions/TreeReceipts/Action/Transfer.tsx @@ -1,23 +1,23 @@ import FaArrowAltCircleRight from '@/components/Icons/FaArrowAltCircleRight'; import { shortenAddress, yoctoToNear } from '@/utils/libs'; import { TransactionActionInfo } from '@/utils/types'; -import useTranslation from 'next-translate/useTranslation'; import TreeNode from '../TreeNode'; -import Link from 'next/link'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; const Transfer = (props: TransactionActionInfo) => { const { args, receiver, action } = props; - const { t } = useTranslation(); + const t = useTranslations(); return ( <>
{' '} - {t ? t('txns:txn.actions.transfer.0') : 'Transferred'} + {t ? t('txn.actions.transfer.0') : 'Transferred'} {args.deposit ? yoctoToNear(args.deposit, true) : args.deposit ?? ''}{' '} Ⓝ {' '} - {t ? t('txns:txn.actions.transfer.1') : 'to'} + {t ? t('txn.actions.transfer.1') : 'to'} & { + locale?: any; + className?: any; + legacyBehavior?: boolean; +}; + +interface ActiveLinkProps extends LinkProps { + children: ReactNode; + activeClassName?: string; + inActiveClassName?: string; + href: string | UrlObject; +} + +const ActiveLink = ({ + children, + activeClassName, + inActiveClassName, + href, + legacyBehavior, + ...props +}: ActiveLinkProps) => { + const asPath = usePathname(); + + const child = Children.only(children) as ReactElement; + const childClassName = child?.props?.className || ' '; + + const hrefString = typeof href === 'string' ? href : href.pathname || ''; + + const className = ( + href === '/' ? asPath === href : asPath.startsWith(hrefString) + ) + ? `${childClassName} ${activeClassName}` + : `${childClassName} ${inActiveClassName}`; + + return ( + + {React.cloneElement(child, { + className: className || null, + })} + + ); +}; + +export default ActiveLink; diff --git a/apps/app/src/components/app/Blocks/Details.tsx b/apps/app/src/components/app/Blocks/Details.tsx new file mode 100644 index 00000000..348e8ff3 --- /dev/null +++ b/apps/app/src/components/app/Blocks/Details.tsx @@ -0,0 +1,259 @@ +'use client'; + +import ErrorMessage from '../common/ErrorMessage'; +import FileSlash from '../Icons/FileSlash'; +import { gasPrice } from '@/utils/near'; +import { BlocksInfo } from '@/utils/types'; +import { networkId } from '@/utils/app/config'; +import { + convertToMetricPrefix, + convertToUTC, + dollarFormat, + gasFee, + getTimeAgoString, + localFormat, + nanoToMilli, +} from '@/utils/app/libs'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; +interface Props { + hash?: any; + data: any; + loading?: any; + price: any; +} + +export default function Details(props: Props) { + const t = useTranslations(); + const { hash, data, price } = props; + const nearPrice = price?.stats[0]?.near_price; + + interface Props { + children?: string; + href: string; + } + const LinkWrapper = (props: Props) => ( + + {props.children} + + ); + + const block: BlocksInfo | null = data?.blocks?.[0]; + const gasUsed = block?.chunks_agg?.gas_used ?? ''; + const gasLimit = block?.chunks_agg?.gas_limit ?? ''; + return ( + <> +
+

+ {block ? ( + t ? ( + <> + {t('block.heading.0') || 'Block'} + + {t('block.heading.1', { + block: block?.block_height + ? localFormat(block?.block_height.toString()) + : '', + }) || + `#${ + block?.block_height + ? localFormat(block?.block_height.toString()) + : '' + }`} + + + ) : ( + <> + Block + + # + {block?.block_height + ? localFormat(block?.block_height.toString()) + : ''} + + + ) + ) : null} +

+
+ {!block ? ( +
+
+
+ } + message="Sorry, We are unable to locate this BlockHash" + mutedText={hash ? hash : ''} + /> +
+
+
+ ) : ( + <> +
+ {networkId === 'testnet' && ( +
+ {t('testnetNotice') || '[ This is a Testnet block only ]'} +
+ )} +
+
+ {t('block.height') || 'Block Height'} +
+
+ {block?.block_height + ? localFormat(block?.block_height.toString()) + : block?.block_height ?? ''} +
+
+
+
+ {t('block.hash') || 'Hash'} +
+
+ {block?.block_hash} +
+
+
+
+ {t('block.timestamp') || 'Timestamp'} +
+
+ {block?.block_timestamp && + `${getTimeAgoString( + nanoToMilli(block?.block_timestamp), + )} (${convertToUTC( + nanoToMilli(block?.block_timestamp), + true, + )}) +UTC`} +
+
+
+
+ {t?.('block.transactions.0') || 'Transactions'} +
+ {block?.transactions_agg?.count && ( +
+ + {t?.('block.transactions.1', { + txns: + localFormat( + block?.transactions_agg?.count?.toString(), + ) || + block?.transactions_agg?.count?.toString() || + 'transactions', + }) || + `${localFormat( + block?.transactions_agg?.count?.toString(), + )} transactions`} + +   + {t?.('block.transactions.2', { + receipts: + localFormat(block?.receipts_agg?.count?.toString()) || + block?.receipts_agg?.count?.toString() || + 'receipts', + }) || + `and ${localFormat( + block?.receipts_agg?.count?.toString(), + )} receipts`} +
+ )} +
+ +
+
+ {t('block.author') || 'Author'} +
+
+ + {block?.author_account_id} + +
+
+
+
+ {t('block.gasUsed') || 'GAS Used'} +
+
+ {gasUsed + ? convertToMetricPrefix(gasUsed.toString()) + 'gas' + : ''} +
+
+
+
+ {t('block.gasLimit') || 'Gas Limit'} +
+
+ {gasLimit + ? convertToMetricPrefix(gasLimit.toString()) + 'gas' + : ''} +
+
+
+
+ {t('block.gasPrice') || 'GAS Price'} +
+
+ {block?.gas_price + ? gasPrice(block?.gas_price.toString()) + : block?.gas_price ?? ''} +
+
+
+
+ {t('block.gasFee') || 'Gas Fee'} +
+
+ {gasUsed && block?.gas_price + ? gasFee(gasUsed.toString(), block?.gas_price.toString()) + + ' Ⓝ' + : ''} +
+
+
+
+ {t('block.parenthash') || 'Parent Hash'} +
+
+ + {block?.prev_block_hash} + +
+
+ {networkId === 'mainnet' && ( + // && date +
+
+ {t('block.price') || 'Price'} +
+
+ {nearPrice && !isNaN(Number(nearPrice)) + ? `$${dollarFormat(Number(nearPrice))} / Ⓝ` + : 'N/A'} +
+
+ )} +
+
Shard Number
+
+ {block?.chunks_agg?.shards?.toString() && + localFormat(block?.chunks_agg?.shards?.toString())} +
+
+
+ + )} + + ); +} diff --git a/apps/app/src/components/app/Blocks/List.tsx b/apps/app/src/components/app/Blocks/List.tsx new file mode 100644 index 00000000..e11b9515 --- /dev/null +++ b/apps/app/src/components/app/Blocks/List.tsx @@ -0,0 +1,296 @@ +'use client'; +import { Suspense, useState } from 'react'; +import ErrorMessage from '../common/ErrorMessage'; +import { BlocksInfo } from '@/utils/types'; + +import { Tooltip } from '@reach/tooltip'; +import Clock from '../Icons/Clock'; +import FaInbox from '../Icons/FaInbox'; +import Skeleton from '../skeleton/common/Skeleton'; +import Table from '../common/Table'; +import { + convertToMetricPrefix, + formatTimestampToString, + gasFee, + getTimeAgoString, + localFormat, + nanoToMilli, + shortenAddress, +} from '@/utils/app/libs'; +import { Link } from '@/i18n/routing'; + +const t = (key: string, p?: any): any => { + p = {}; + const simulateAbsence = true; + return simulateAbsence ? undefined : { key, p }; +}; + +const List = ({ + data, + totalCount, + countLoading, + apiUrl, + setUrl, + error, +}: any) => { + const [showAge, setShowAge] = useState(true); + const [page, setPage] = useState(1); + const errorMessage = t('noBlocks') || 'No blocks!'; + const [address, setAddress] = useState(''); + + const onHandleMouseOver = (e: any, id: string) => { + e.preventDefault(); + setAddress(id); + }; + const handleMouseLeave = () => { + setAddress(''); + }; + const blocks = data?.blocks; + const start = data?.blocks?.[0]; + const end = data?.blocks?.[data?.blocks?.length - 1]; + const count = totalCount?.blocks?.[0]?.count || 0; + const cursor = data?.cursor; + const toggleShowAge = () => setShowAge((s) => !s); + const columns: any = [ + { + header: {t('blocks') || 'BLOCK'}, + key: 'block_hash', + cell: (row: BlocksInfo) => ( + + + {row?.block_height + ? localFormat(row?.block_height) + : row?.block_height ?? ''} + + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10 font-medium', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: ( +
+ + + +
+ ), + key: 'block_timestamp', + cell: (row: BlocksInfo) => ( + + + + {!showAge + ? row?.block_timestamp + ? formatTimestampToString(nanoToMilli(row?.block_timestamp)) + : '' + : row?.block_timestamp + ? getTimeAgoString(nanoToMilli(row?.block_timestamp)) + : ''} + + + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10 w-48', + }, + { + header: {t('txn') || 'TXN'}, + key: 'count', + cell: (row: BlocksInfo) => ( + + + {row?.transactions_agg?.count + ? localFormat(row?.transactions_agg?.count) + : row?.transactions_agg?.count ?? ''} + + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: {t('block.receipt') || 'RECEIPT'}, + key: 'count', + cell: (row: BlocksInfo) => ( + + {row?.receipts_agg?.count + ? localFormat(row?.receipts_agg?.count) + : row?.receipts_agg?.count ?? ''} + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: {t('miner') || 'AUTHOR'}, + key: 'author_account_id', + cell: (row: BlocksInfo) => ( + + onHandleMouseOver(e, row?.author_account_id)} + onMouseLeave={handleMouseLeave} + > + {shortenAddress(row?.author_account_id ?? '')} + + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10 font-medium', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: {t('block.gasUsed') || 'GAS USED'}, + key: 'gas_used', + cell: (row: BlocksInfo) => ( + + {row?.chunks_agg?.gas_used !== null + ? convertToMetricPrefix(row?.chunks_agg?.gas_used) + 'gas' + : ''} + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: {t('block.gasLimit') || 'GAS LIMIT'}, + key: 'gas_limit', + cell: (row: BlocksInfo) => ( + {convertToMetricPrefix(row?.chunks_agg?.gas_limit ?? 0)}gas + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + { + header: {t('block.gasFee') || 'GAS FEE'}, + key: 'gas_price', + cell: (row: BlocksInfo) => ( + + {row?.chunks_agg?.gas_used + ? gasFee(row?.chunks_agg?.gas_used, row?.gas_price) + : row?.chunks_agg?.gas_used ?? ''}{' '} + Ⓝ + + ), + tdClassName: + 'px-6 py-4 whitespace-nowrap text-sm text-nearblue-600 dark:text-neargray-10', + thClassName: + 'px-6 py-2 text-left text-xs font-semibold text-nearblue-600 dark:text-neargray-10 uppercase tracking-wider whitespace-nowrap', + }, + ]; + return ( +
+ + +
+ } + > +
+

+ {data && ( + + {(t && + t('listing', { + from: start?.block_height + ? localFormat(String(start?.block_height)) + : '', + to: end?.block_height + ? localFormat(String(end?.block_height)) + : '', + count: localFormat(String(count)), + })) || + `Block #${ + start?.block_height + ? localFormat(String(start?.block_height)) + : '' + } to #${ + end?.block_height + ? localFormat(String(end?.block_height)) + : '' + } (Total of ${localFormat(String(count))} blocks)`} + + )} +

+
+ + } + message={errorMessage} + mutedText="Please try again later" + /> + } + /> + + ); +}; +export default List; diff --git a/apps/app/src/components/app/Collapse.tsx b/apps/app/src/components/app/Collapse.tsx new file mode 100644 index 00000000..81ebad5d --- /dev/null +++ b/apps/app/src/components/app/Collapse.tsx @@ -0,0 +1,35 @@ +import React, { ReactNode, useState } from 'react'; + +interface CollapseProps { + children: ReactNode; + trigger: ({ + show, + onClick, + }: { + show: boolean; + onClick: React.MouseEventHandler; + }) => React.ReactNode; +} + +const Collapse = ({ children, trigger }: CollapseProps) => { + const [show, setShow] = useState(false); + + const onClick = () => { + setShow((s) => !s); + }; + + return ( + <> + {trigger({ show, onClick })} +
+ {children} +
+ + ); +}; + +export default Collapse; diff --git a/apps/app/src/components/app/Error.tsx b/apps/app/src/components/app/Error.tsx new file mode 100644 index 00000000..8648bbaa --- /dev/null +++ b/apps/app/src/components/app/Error.tsx @@ -0,0 +1,23 @@ +import Head from 'next/head'; + +const Error = () => { + return ( + <> +
+ + NearBlocks - Page not Found + +
+
+
+ 404 +
+
+
+
+
+ + ); +}; + +export default Error; diff --git a/apps/app/src/components/app/Icons/Arrow.tsx b/apps/app/src/components/app/Icons/Arrow.tsx new file mode 100644 index 00000000..c799bcbf --- /dev/null +++ b/apps/app/src/components/app/Icons/Arrow.tsx @@ -0,0 +1,21 @@ +import React, { SVGProps } from 'react'; + +const Arrow = (props: SVGProps) => { + return ( + + + + ); +}; + +export default Arrow; diff --git a/apps/app/src/components/app/Icons/ArrowDown.tsx b/apps/app/src/components/app/Icons/ArrowDown.tsx new file mode 100644 index 00000000..43e0f63e --- /dev/null +++ b/apps/app/src/components/app/Icons/ArrowDown.tsx @@ -0,0 +1,18 @@ +import React, { SVGProps } from 'react'; + +const ArrowDown = (props: SVGProps) => { + return ( + + + + + ); +}; + +export default ArrowDown; diff --git a/apps/app/src/components/app/Icons/ArrowUp.tsx b/apps/app/src/components/app/Icons/ArrowUp.tsx new file mode 100644 index 00000000..3756f5f3 --- /dev/null +++ b/apps/app/src/components/app/Icons/ArrowUp.tsx @@ -0,0 +1,19 @@ +interface Props { + className: string; +} +const ArrowUp = (props: Props) => { + return ( + + + + + ); +}; + +export default ArrowUp; diff --git a/apps/app/src/components/app/Icons/Button.tsx b/apps/app/src/components/app/Icons/Button.tsx new file mode 100644 index 00000000..890648e9 --- /dev/null +++ b/apps/app/src/components/app/Icons/Button.tsx @@ -0,0 +1,101 @@ +import { Tooltip } from '@reach/tooltip'; +import { useEffect, useRef, useState } from 'react'; +import CopyIcon from './CopyIcon'; +import QrCode from '../common/QrCode'; +import Clipboard from 'clipboard'; +import QRCodeIcon from './QRCodeIcon'; +import { DialogOverlay, DialogContent } from '@reach/dialog'; +import CloseCircle from './CloseCircle'; + +interface Props { + address: string; + theme?: string; +} + +const Buttons = ({ address }: Props) => { + const ref = useRef(null); + const [isOpen, setIsOpen] = useState(false); + const [showTooltip, setShowTooltip] = useState(false); + + useEffect(() => { + if (!ref.current) { + return undefined; + } + + const clip = new Clipboard(ref.current, { + text() { + return address || ''; + }, + }); + + clip.on('success', () => { + setShowTooltip((t) => !t); + + setTimeout(() => setShowTooltip((t) => !t), 1500); + }); + + return () => clip.destroy(); + }, [address]); + + const onToggle = () => setIsOpen((open) => !open); + + return ( + <> + + + + {showTooltip && ( + + Copied! + + )} + + + + + + + + + +
+

{address}

+ +
+
+ +
+
+
+ + ); +}; + +export default Buttons; diff --git a/apps/app/src/components/app/Icons/Check.tsx b/apps/app/src/components/app/Icons/Check.tsx new file mode 100644 index 00000000..3698cf84 --- /dev/null +++ b/apps/app/src/components/app/Icons/Check.tsx @@ -0,0 +1,14 @@ +import { SVGProps } from 'react'; + +const Check = (props: SVGProps) => ( + + + +); + +export default Check; diff --git a/apps/app/src/components/app/Icons/Clock.tsx b/apps/app/src/components/app/Icons/Clock.tsx new file mode 100644 index 00000000..ae33d5c4 --- /dev/null +++ b/apps/app/src/components/app/Icons/Clock.tsx @@ -0,0 +1,26 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} + +const Clock = (props: Props) => ( + +); + +export default Clock; diff --git a/apps/app/src/components/app/Icons/CloseCircle.tsx b/apps/app/src/components/app/Icons/CloseCircle.tsx new file mode 100644 index 00000000..56ffcaee --- /dev/null +++ b/apps/app/src/components/app/Icons/CloseCircle.tsx @@ -0,0 +1,26 @@ +interface Props { + className?: string; + onClick?: (name: string) => void; +} +const CloseCircle = (props: Props) => { + const handleClick = () => { + if (props.onClick) { + props.onClick('All'); + } + }; + return ( + + + + + ); +}; + +export default CloseCircle; diff --git a/apps/app/src/components/app/Icons/CopyIcon.tsx b/apps/app/src/components/app/Icons/CopyIcon.tsx new file mode 100644 index 00000000..1eec2cf0 --- /dev/null +++ b/apps/app/src/components/app/Icons/CopyIcon.tsx @@ -0,0 +1,24 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} + +const CopyIcon = (props: Props) => { + return ( + + + + + ); +}; +export default CopyIcon; diff --git a/apps/app/src/components/app/Icons/Download.tsx b/apps/app/src/components/app/Icons/Download.tsx new file mode 100644 index 00000000..d9921029 --- /dev/null +++ b/apps/app/src/components/app/Icons/Download.tsx @@ -0,0 +1,20 @@ +const Download = () => { + return ( + + + + ); +}; + +export default Download; diff --git a/apps/app/src/components/app/Icons/FaCheckCircle.tsx b/apps/app/src/components/app/Icons/FaCheckCircle.tsx new file mode 100644 index 00000000..c38b81d2 --- /dev/null +++ b/apps/app/src/components/app/Icons/FaCheckCircle.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +const FaCheckCircle = () => { + return ( + + + + ); +}; +export default FaCheckCircle; diff --git a/apps/app/src/components/app/Icons/FaChevronLeft.tsx b/apps/app/src/components/app/Icons/FaChevronLeft.tsx new file mode 100644 index 00000000..917e765c --- /dev/null +++ b/apps/app/src/components/app/Icons/FaChevronLeft.tsx @@ -0,0 +1,19 @@ +const FaChevronLeft = () => { + return ( + + + + ); +}; + +export default FaChevronLeft; diff --git a/apps/app/src/components/app/Icons/FaChevronRight.tsx b/apps/app/src/components/app/Icons/FaChevronRight.tsx new file mode 100644 index 00000000..134db695 --- /dev/null +++ b/apps/app/src/components/app/Icons/FaChevronRight.tsx @@ -0,0 +1,19 @@ +const FaChevronRight = () => { + return ( + + + + ); +}; + +export default FaChevronRight; diff --git a/apps/app/src/components/app/Icons/FaExternalLinkAlt.tsx b/apps/app/src/components/app/Icons/FaExternalLinkAlt.tsx new file mode 100644 index 00000000..db39e066 --- /dev/null +++ b/apps/app/src/components/app/Icons/FaExternalLinkAlt.tsx @@ -0,0 +1,9 @@ +const FaExternalLinkAlt = () => { + return ( + + + + ); +}; + +export default FaExternalLinkAlt; diff --git a/apps/app/src/components/app/Icons/FaHourglassStart.tsx b/apps/app/src/components/app/Icons/FaHourglassStart.tsx new file mode 100644 index 00000000..8ee6c08e --- /dev/null +++ b/apps/app/src/components/app/Icons/FaHourglassStart.tsx @@ -0,0 +1,20 @@ +interface Props { + className?: string; +} +const FaHourglassStart = (props: Props) => { + return ( + + + + ); +}; + +export default FaHourglassStart; diff --git a/apps/app/src/components/app/Icons/FaInbox.tsx b/apps/app/src/components/app/Icons/FaInbox.tsx new file mode 100644 index 00000000..a81240f2 --- /dev/null +++ b/apps/app/src/components/app/Icons/FaInbox.tsx @@ -0,0 +1,16 @@ +const FaInbox = () => { + return ( + + + + ); +}; +export default FaInbox; diff --git a/apps/app/src/components/app/Icons/FaTimesCircle.tsx b/apps/app/src/components/app/Icons/FaTimesCircle.tsx new file mode 100644 index 00000000..67d24b1d --- /dev/null +++ b/apps/app/src/components/app/Icons/FaTimesCircle.tsx @@ -0,0 +1,12 @@ +const FaTimesCircle = () => { + return ( + + + + ); +}; + +export default FaTimesCircle; diff --git a/apps/app/src/components/app/Icons/FileSlash.tsx b/apps/app/src/components/app/Icons/FileSlash.tsx new file mode 100644 index 00000000..7c44bb7c --- /dev/null +++ b/apps/app/src/components/app/Icons/FileSlash.tsx @@ -0,0 +1,18 @@ +const FileSlash = () => { + return ( + + + + ); +}; + +export default FileSlash; diff --git a/apps/app/src/components/app/Icons/Filter.tsx b/apps/app/src/components/app/Icons/Filter.tsx new file mode 100644 index 00000000..43fd3c0e --- /dev/null +++ b/apps/app/src/components/app/Icons/Filter.tsx @@ -0,0 +1,19 @@ +interface Props { + className: string; +} +const Filter = (props: Props) => { + return ( + + + + + ); +}; + +export default Filter; diff --git a/apps/app/src/components/app/Icons/Menu.tsx b/apps/app/src/components/app/Icons/Menu.tsx new file mode 100644 index 00000000..b7b37ede --- /dev/null +++ b/apps/app/src/components/app/Icons/Menu.tsx @@ -0,0 +1,21 @@ +import React, { SVGProps } from 'react'; + +const Menu = (props: SVGProps) => { + return ( + + + + + ); +}; + +export default Menu; diff --git a/apps/app/src/components/app/Icons/QRCodeIcon.tsx b/apps/app/src/components/app/Icons/QRCodeIcon.tsx new file mode 100644 index 00000000..a47f7b56 --- /dev/null +++ b/apps/app/src/components/app/Icons/QRCodeIcon.tsx @@ -0,0 +1,25 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} + +const QRCodeIcon = (props: Props) => { + return ( + + + + + ); +}; + +export default QRCodeIcon; diff --git a/apps/app/src/components/app/Icons/Question.tsx b/apps/app/src/components/app/Icons/Question.tsx new file mode 100644 index 00000000..8ea52d79 --- /dev/null +++ b/apps/app/src/components/app/Icons/Question.tsx @@ -0,0 +1,25 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} + +const Question = (props: Props) => { + return ( + + + + + ); +}; + +export default Question; diff --git a/apps/app/src/components/app/Icons/Rpc.tsx b/apps/app/src/components/app/Icons/Rpc.tsx new file mode 100644 index 00000000..fdecbb7a --- /dev/null +++ b/apps/app/src/components/app/Icons/Rpc.tsx @@ -0,0 +1,14 @@ +import { SVGProps } from 'react'; + +const Rpc = (props: SVGProps) => ( + + + +); + +export default Rpc; diff --git a/apps/app/src/components/app/Icons/SearchIcon.tsx b/apps/app/src/components/app/Icons/SearchIcon.tsx new file mode 100644 index 00000000..fe6ad5ec --- /dev/null +++ b/apps/app/src/components/app/Icons/SearchIcon.tsx @@ -0,0 +1,24 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} +const SearchIcon = (props: Props) => { + return ( + + + + + ); +}; + +export default SearchIcon; diff --git a/apps/app/src/components/app/Icons/SortIcon.tsx b/apps/app/src/components/app/Icons/SortIcon.tsx new file mode 100644 index 00000000..01d15b74 --- /dev/null +++ b/apps/app/src/components/app/Icons/SortIcon.tsx @@ -0,0 +1,16 @@ +import ArrowUp from './ArrowUp'; + +interface Props { + order: string; +} +const SortIcon = (props: Props) => { + return ( + + ); +}; + +export default SortIcon; diff --git a/apps/app/src/components/app/Icons/Status.tsx b/apps/app/src/components/app/Icons/Status.tsx new file mode 100644 index 00000000..14817b82 --- /dev/null +++ b/apps/app/src/components/app/Icons/Status.tsx @@ -0,0 +1,55 @@ +import FaCheckCircle from './FaCheckCircle'; +import FaHourglassStart from './FaHourglassStart'; +import FaTimesCircle from './FaTimesCircle'; + +interface Props { + status: boolean; + showLabel: boolean; +} + +const getOptions = (status: boolean) => { + switch (status) { + case null: + return { + bg: 'bg-yellow-50 dark:bg-black', + text: 'text-yellow-500', + icon: FaHourglassStart, + label: 'Pending', + }; + case false: + return { + bg: 'bg-red-50 dark:bg-black', + text: 'text-red-500', + icon: FaTimesCircle, + label: 'Failure', + }; + + default: + return { + bg: 'bg-emerald-50 dark:bg-black', + text: 'text-emerald-500', + icon: FaCheckCircle, + label: 'Success', + }; + } +}; + +const TxnStatus = (props: Props) => { + const option = getOptions(props.status); + const Icon = option.icon; + + return ( +
+ + + {props.showLabel && {option.label}} + +
+ ); +}; + +export default TxnStatus; diff --git a/apps/app/src/components/app/Icons/User.tsx b/apps/app/src/components/app/Icons/User.tsx new file mode 100644 index 00000000..cb4bfe85 --- /dev/null +++ b/apps/app/src/components/app/Icons/User.tsx @@ -0,0 +1,20 @@ +import React, { SVGProps } from 'react'; + +const User = (props: SVGProps) => { + return ( + + + + ); +}; + +export default User; diff --git a/apps/app/src/components/app/Icons/WarningIcon.tsx b/apps/app/src/components/app/Icons/WarningIcon.tsx new file mode 100644 index 00000000..a7f9c7ba --- /dev/null +++ b/apps/app/src/components/app/Icons/WarningIcon.tsx @@ -0,0 +1,23 @@ +/** + * @interface Props + * @param {string} [className] - The CSS class name(s) for styling purposes. + */ + +interface Props { + className: string; +} +const WarningIcon = (props: Props) => { + return ( + + + + ); +}; + +export default WarningIcon; diff --git a/apps/app/src/components/app/Layouts/Footer.tsx b/apps/app/src/components/app/Layouts/Footer.tsx new file mode 100644 index 00000000..64c7bba8 --- /dev/null +++ b/apps/app/src/components/app/Layouts/Footer.tsx @@ -0,0 +1,210 @@ +'use client'; +import Image from 'next/legacy/image'; +import Arrow from '../Icons/Arrow'; +import { useTheme } from 'next-themes'; +import { useTranslations } from 'next-intl'; +import { Link } from '@/i18n/routing'; + +const Footer = () => { + const { theme } = useTheme(); + const currentDate = new Date(); + const t = useTranslations(); + + return ( + + ); +}; + +export default Footer; diff --git a/apps/app/src/components/app/Layouts/Header.tsx b/apps/app/src/components/app/Layouts/Header.tsx new file mode 100644 index 00000000..db50786a --- /dev/null +++ b/apps/app/src/components/app/Layouts/Header.tsx @@ -0,0 +1,754 @@ +'use client'; +import NextLink from 'next/link'; +import Image from 'next/legacy/image'; +import React, { Suspense, useMemo, useState } from 'react'; +import { useAuthStore } from '@/stores/auth'; + +import Collapse from '../Collapse'; +import Menu from '../Icons/Menu'; +import ArrowDown from '../Icons/ArrowDown'; +import ActiveLink from '../ActiveLink'; +import Skeleton from '@/components/skeleton/common/Skeleton'; +import { dollarFormat, nanoToMilli } from '@/utils/libs'; +import User from '../Icons/User'; +import Rpc from '../Icons/Rpc'; +import dynamic from 'next/dynamic'; +import { useTheme } from 'next-themes'; +import { networkId } from '@/utils/app/config'; +import { BlocksInfo, Stats } from '@/utils/types'; +import { Link, routing, usePathname } from '@/i18n/routing'; +import { useTranslations } from 'next-intl'; +import Search from '../common/Search'; + +const menus = [ + { + id: 1, + title: 'header.menu.home', + fallbackText: 'Home', + link: '/', + submenu: [], + }, + { + id: 2, + title: 'header.menu.blockchain', + fallbackText: 'Blockchain', + submenu: [ + { + id: 1, + title: 'header.menu.viewBlocks', + fallbackText: 'View Blocks', + link: '/blocks', + }, + { + id: 2, + title: 'header.menu.viewTxns', + fallbackText: 'View Transactions', + link: '/txns', + }, + { + id: 4, + title: 'header.menu.charts', + fallbackText: 'Charts', + link: '/charts', + }, + { + id: 5, + title: 'header.menu.nodeExplorer', + fallbackText: 'Node Explorer', + link: '/node-explorer', + }, + ], + }, + { + id: 3, + title: 'header.menu.tokens', + fallbackText: 'Tokens', + submenu: [ + { + id: 1, + title: 'header.menu.toptoken', + fallbackText: 'Top Tokens', + link: '/tokens', + }, + { + id: 2, + title: 'header.menu.viewTokenTrasfers', + fallbackText: 'View Token Transfers', + link: '/tokentxns', + }, + { + id: 3, + title: 'header.menu.topnft', + fallbackText: 'Top NFTs', + link: '/nft-tokens', + }, + { + id: 4, + title: 'header.menu.viewNftTrasfers', + fallbackText: 'View NFT Transfers', + link: '/nft-tokentxns', + }, + ], + }, +]; + +const languages = [ + { + title: '한국어', + locale: 'kr', + }, + { + title: 'Bahasa', + locale: 'id', + }, + { + title: '汉语 (Simplified)', + locale: 'zh-cn', + }, + { + title: '漢語 (Traditional)', + locale: 'zh-hk', + }, + { + title: 'Українська', + locale: 'ua', + }, + { + title: 'Русский', + locale: 'ru', + }, + { + title: 'Tiếng Việt', + locale: 'vi', + }, + { + title: 'Español', + locale: 'es', + }, + { + title: 'Français', + locale: 'fr', + }, + { + title: '日本語', + locale: 'jp', + }, + { + title: 'Filipino', + locale: 'ph', + }, + { + title: 'ภาษาไทย', + locale: 'th', + }, + { + title: 'Italiano', + locale: 'it', + }, +]; + +const Header = ({ + stats: statsDetails, + block: latestBlocks, + handleFilterAndKeyword, +}: any) => { + const stats: Stats | undefined = statsDetails?.stats?.[0]; + const block: BlocksInfo | undefined = latestBlocks?.blocks?.[0]; + + const [open, setOpen] = useState(false); + const requestSignInWithWallet = useAuthStore( + (store) => store.requestSignInWithWallet, + ); + const signedIn = useAuthStore((store) => store?.signedIn); + const accountId = useAuthStore((store) => store?.accountId); + const logOut = useAuthStore((store) => store?.logOut); + const user = signedIn; + const nearPrice = stats?.near_price ?? ''; + const t = useTranslations(); + + const RpcMenu = dynamic(() => import('./RpcMenu'), { + ssr: false, + }); + const pathname = usePathname(); + const { theme, setTheme } = useTheme(); + const status = useMemo(() => { + if (block?.block_timestamp) { + const timestamp = nanoToMilli(block?.block_timestamp); + + const utcDate = Date.parse(new Date(timestamp).toISOString()); + const currentTime = Date.now(); + + if ((currentTime - utcDate) / (1000 * 60) > 10) { + return false; + } + } + return true; + }, [block]); + + const showSearch = pathname !== '/'; + const userLoading = false; + + const onSignOut = () => { + logOut(); + }; + + type LinkProps = Omit & { + href: string; + locale: any; + children: any; + className: any; + }; + + const IntlLink: React.FC = (props) => { + if (!routing?.locales?.includes(props.locale)) { + console.error(`Invalid locale: ${props.locale}`); + return null; + } + + return ; + }; + + return ( +
+ {!status && ( +
+
+ {t('outofSync') || + 'This blockchain explorer is out of sync. Some blocks or transactions may be delayed.'} +
+
+ )} +
+
+
+
+ + + + + + {showSearch && ( + + +
+ } + > +
+ {networkId === 'testnet' ? ( +

+ Testnet Network +

+ ) : ( + <> + {nearPrice ? ( +
+ +

+ $ + {stats?.near_price + ? dollarFormat(stats?.near_price) + : stats?.near_price ?? ''} +

+ {Number(stats?.change_24) > 0 ? ( + <> + + (+ + {stats?.change_24 + ? dollarFormat(stats?.change_24) + : stats?.change_24 ?? ''} + %) + + + ) : ( + + {' '} + ( + {stats?.change_24 + ? dollarFormat(stats?.change_24) + : stats?.change_24 ?? ''} + %) + + )} +
+ ) : ( + '' + )} + + )} +
+ + )} +
+
+ + +
+
+
+ {showSearch && ( +
+
+ +
+
+ )} + +
+
+
+ + ); +}; +export default Header; diff --git a/apps/app/src/components/app/Layouts/Menu.tsx b/apps/app/src/components/app/Layouts/Menu.tsx new file mode 100644 index 00000000..6a458af0 --- /dev/null +++ b/apps/app/src/components/app/Layouts/Menu.tsx @@ -0,0 +1,118 @@ +import React, { ReactNode } from 'react'; +import Check from '../Icons/Check'; +import { Link } from '@/i18n/routing'; + +type MenuProps = { + children: ReactNode; + className?: string; +}; + +type MenuItemProps = { + className?: string; + dropdown?: ReactNode; + onClick?: () => void; + trigger: ReactNode; +}; + +type MenuDropdownProps = { + children?: ReactNode; + className?: string; +}; + +type MenuTitleProps = { + children: ReactNode; + className?: string; +}; + +type MenuLinkProps = { + checked: boolean; + children: ReactNode; + href: string; +}; + +type MenuButtonProps = { + checked: boolean; + children: ReactNode; + onClick: () => void; +}; + +export const Menu = ({ children, className }: MenuProps) => { + return ( + + ); +}; + +export const MenuItem = ({ + className, + dropdown, + onClick, + trigger, +}: MenuItemProps) => { + return ( +
  • + + {dropdown && dropdown} +
  • + ); +}; + +export const MenuDropdown = ({ children, className }: MenuDropdownProps) => { + return ( +
    +
      + {children} +
    +
    + ); +}; + +export const MenuTitle = ({ children, className }: MenuTitleProps) => { + return ( +
  • + {children} +
  • + ); +}; + +export const MenuLink = ({ checked, children, href }: MenuLinkProps) => { + return ( +
  • + + {checked && } + {children} + +
  • + ); +}; + +export const MenuButton = ({ checked, children, onClick }: MenuButtonProps) => { + return ( +
  • + +
  • + ); +}; diff --git a/apps/app/src/components/app/Layouts/RpcMenu.tsx b/apps/app/src/components/app/Layouts/RpcMenu.tsx new file mode 100644 index 00000000..ef4c9529 --- /dev/null +++ b/apps/app/src/components/app/Layouts/RpcMenu.tsx @@ -0,0 +1,25 @@ +import { useRpcStore } from '@/stores/rpc'; +import { MenuButton, MenuTitle } from './Menu'; +import { RpcProviders } from '@/utils/rpc'; + +const RpcMenu = () => { + const rpcUrl = useRpcStore((state) => state.rpc); + const setRpc = useRpcStore((state) => state.setRpc); + + return ( + <> + RPC + {RpcProviders.map((provider) => ( + setRpc(provider.url)} + > + {provider.name} + + ))} + + ); +}; + +export default RpcMenu; diff --git a/apps/app/src/components/app/Layouts/index.tsx b/apps/app/src/components/app/Layouts/index.tsx new file mode 100644 index 00000000..dd29ae38 --- /dev/null +++ b/apps/app/src/components/app/Layouts/index.tsx @@ -0,0 +1,44 @@ +'use client'; +import { ReactNode } from 'react'; +import Header from './Header'; +import Footer from './Footer'; +import { usePathname } from 'next/navigation'; + +interface LayoutProps { + children: ReactNode; + notice?: ReactNode; + stats: any; + blocks: any; + handleFilterAndKeyword: any; +} + +const Layout = ({ + children, + notice, + stats, + blocks, + handleFilterAndKeyword, +}: LayoutProps) => { + const pathname = usePathname(); + const className = + pathname === '/404' + ? 'bg-white dark:bg-black-300' + : 'bg-neargray-25 dark:bg-black-300 '; + + return ( +
    + {notice} +
    +
    +
    +
    {children}
    +
    +
    + ); +}; + +export default Layout; diff --git a/apps/app/src/components/app/SponserdText.tsx b/apps/app/src/components/app/SponserdText.tsx new file mode 100644 index 00000000..3922b62e --- /dev/null +++ b/apps/app/src/components/app/SponserdText.tsx @@ -0,0 +1,65 @@ +'use client'; +import React, { useEffect, useState } from 'react'; +import Skeleton from './skeleton/common/Skeleton'; + +const userApiUrl = process.env.NEXT_PUBLIC_USER_API_URL; +const SponserdText: React.FC = () => { + const [isMobile, setIsMobile] = useState(false); + const [htmlContent, setHtmlContent] = useState(''); + + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth < 1024); + }; + handleResize(); + window.addEventListener('resize', handleResize); + + return () => window.removeEventListener('resize', handleResize); + }, []); + + // Use a promise-based approach to fetch HTML content + useEffect(() => { + const fetchHtmlContent = async () => { + try { + const response = await fetch( + `${userApiUrl}approved-campaigns/text-ads`, + ); + + if (response.ok) { + const html = await response.text(); + setHtmlContent(html); + } else { + console.error('Error fetching HTML content:', response.statusText); + } + } catch (error) { + console.error('Error fetching HTML content:', error); + } + }; + + fetchHtmlContent(); + }, []); + + if (isMobile) { + return ( +
    + {htmlContent && ( +
    + )} +
    + ); + } else { + return ( +
    + {htmlContent ? ( +
    +
    +
    + ) : ( + + )} +
    + ); + } +}; + +export default SponserdText; diff --git a/apps/app/src/components/app/SwitchButton.tsx b/apps/app/src/components/app/SwitchButton.tsx new file mode 100644 index 00000000..27ecc98b --- /dev/null +++ b/apps/app/src/components/app/SwitchButton.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const SwitchButton = ({ selected, onChange }: any) => { + return ( +
    +
    +
    + ); +}; + +export default SwitchButton; diff --git a/apps/app/src/components/app/common/CursorPaginator.tsx b/apps/app/src/components/app/common/CursorPaginator.tsx new file mode 100644 index 00000000..61cf302a --- /dev/null +++ b/apps/app/src/components/app/common/CursorPaginator.tsx @@ -0,0 +1,87 @@ +'use client'; +import { useIntlRouter } from '@/i18n/routing'; +import { formatWithCommas } from '@/utils/libs'; +import { useSearchParams } from 'next/navigation'; +interface PaginatorProps { + apiUrl?: string; + cursor: string | undefined; + isLoading?: boolean; +} +const CursorPaginator = (props: PaginatorProps) => { + const { cursor, isLoading } = props; + const intlRouter = useIntlRouter(); + const searchParams = useSearchParams(); + const page = searchParams?.get('page') || '1'; + + const handleNextPage = () => { + if (cursor) { + const currentUrl = new URL(window?.location.href); + const params = new URLSearchParams(currentUrl?.search); + params.set('page', String(Number(page) + 1)); + params.set('cursor', `${cursor}`); + + const newUrl = `${currentUrl?.pathname}?${params?.toString()}`; + + intlRouter.push(newUrl); + } + }; + + const onFirst = () => { + const currentUrl = new URL(window.location.href); + const params = new URLSearchParams(currentUrl.search); + + params.delete('cursor'); + params.delete('page'); + + const newUrl = `${currentUrl.pathname}?${params.toString()}`; + + intlRouter.replace(newUrl); + }; + + return ( + <> +
    +
    +
    +
    + + + +
    +
    +
    + + ); +}; +export default CursorPaginator; diff --git a/apps/app/src/components/app/common/ErrorMessage.tsx b/apps/app/src/components/app/common/ErrorMessage.tsx new file mode 100644 index 00000000..e52082a7 --- /dev/null +++ b/apps/app/src/components/app/common/ErrorMessage.tsx @@ -0,0 +1,23 @@ +interface Props { + icons: SVGElement | any; + message: string; + mutedText: string; +} +const ErrorMessage = ({ icons, message, mutedText }: Props) => { + return ( +
    +
    + + {icons} + +
    + +

    + {message} +

    + +

    {mutedText}

    +
    + ); +}; +export default ErrorMessage; diff --git a/apps/app/src/components/app/common/Filters.tsx b/apps/app/src/components/app/common/Filters.tsx new file mode 100644 index 00000000..760afed2 --- /dev/null +++ b/apps/app/src/components/app/common/Filters.tsx @@ -0,0 +1,38 @@ +import { capitalize, stripEmpty } from '@/utils/libs'; +import CloseCircle from '../Icons/CloseCircle'; + +interface FiltersProps { + filters: { [key: string]: any }; // Adjust the type as needed + onClear?: () => void; +} + +const Filters: React.FC = ({ + filters = {}, + onClear = () => {}, +}) => { + const stripped = Object.keys(stripEmpty(filters)); + + if (!stripped.length) return null; + + return ( +
    + Filtered By: + + {stripped.map((key) => ( + + {capitalize(key)}:{' '} + + {filters[key]} + + + ))} + + +
    + ); +}; + +export default Filters; diff --git a/apps/app/src/components/app/common/Paginator.tsx b/apps/app/src/components/app/common/Paginator.tsx new file mode 100644 index 00000000..08d0bfcc --- /dev/null +++ b/apps/app/src/components/app/common/Paginator.tsx @@ -0,0 +1,130 @@ +'use client'; +import useTranslation from 'next-translate/useTranslation'; +import FaChevronLeft from '../Icons/FaChevronLeft'; +import FaChevronRight from '../Icons/FaChevronRight'; +import { useSearchParams } from 'next/navigation'; +import { useIntlRouter, usePathname } from '@/i18n/routing'; +interface PaginatorProps { + count: number; + limit: number; + pageLimit: number; + shallow?: boolean; + isLoading?: boolean; + page?: any; + setPage?: any; +} +const Paginator = (props: PaginatorProps) => { + const { t } = useTranslation('common'); + const intlRouter = useIntlRouter(); + const searchParams = useSearchParams(); + const pathname = usePathname(); + const page = searchParams?.get('page'); + const currentPage = page ? Number(page) : 1; + let pages: number; + const { count, limit, pageLimit = 200 } = props; + if (count > 0) { + pages = Math.ceil(count / limit); + } else { + pages = 1; + } + + pages = pages > pageLimit ? pageLimit : pages; + const onPrev = () => { + if (currentPage <= 1) return; + const newPage = currentPage - 1; + const newParams = new URLSearchParams(searchParams || ''); + newParams.set('page', String(newPage)); + + intlRouter.push(`${pathname}?${newParams.toString()}`); + }; + + const onNext = () => { + if (currentPage >= pages) return; + const newPage = currentPage + 1; + const newParams = new URLSearchParams(searchParams || ''); + newParams.set('page', String(newPage)); + intlRouter.push(`${pathname}?${newParams.toString()}`); + }; + + const onFirst = () => { + const newParams = new URLSearchParams(searchParams || ''); + newParams.set('page', '1'); + intlRouter.push(`${pathname}?${newParams.toString()}`); + }; + + const onLast = () => { + const newParams = new URLSearchParams(searchParams || ''); + newParams.set('page', pages.toString()); + intlRouter.push(`${pathname}?${newParams.toString()}`); + }; + return ( +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + ); +}; +export default Paginator; diff --git a/apps/app/src/components/app/common/QrCode.tsx b/apps/app/src/components/app/common/QrCode.tsx new file mode 100644 index 00000000..55ade796 --- /dev/null +++ b/apps/app/src/components/app/common/QrCode.tsx @@ -0,0 +1,64 @@ +import { useTheme } from 'next-themes'; + +/** + * @interface Props + * @param {string} [value] - The data value to be encoded as a QR code (e.g., a URL, text, etc.). + * @param {number} [width] - The width of the QR code component. + * @param {number} [height] - The height of the QR code component. + */ +interface Props { + value: string; + width: number; + height: number; + theme?: string; +} + +const QrCode = (props: Props) => { + const { theme } = useTheme(); + + const colorDark = theme === 'dark' ? '#ffffff' : '#000000'; + const colorLight = theme === 'dark' ? '#000000' : '#ffffff'; + + const srcData = ` + + +
    + + + + + + `; + + return ( +
    +