diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index da16cd19358..30e18010ae6 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -10,7 +10,6 @@ title: '[Task(*)]: release version x.y.z' - [ ] Edit `crates/iota-open-rpc/spec/openrpc.json` - [ ] Update `sdk/typescript/src/version.ts` (`pnpm sdk build`) - [ ] Update `Cargo.lock` (`cargo check`) -- [ ] Update `crates/iota-framework/packages/deepbook/Move.lock` - [ ] Update `crates/iota-framework/packages/iota-framework/Move.lock` - [ ] Update `crates/iota-framework/packages/iota-system/Move.lock` - [ ] Update `crates/iota-framework/packages/move-stdlib/Move.lock` diff --git a/.github/workflows/_rust_tests.yml b/.github/workflows/_rust_tests.yml index ce9f40d94c0..6abe2108be8 100644 --- a/.github/workflows/_rust_tests.yml +++ b/.github/workflows/_rust_tests.yml @@ -72,8 +72,7 @@ jobs: check-unused-deps: name: Check Unused Dependencies (${{ matrix.flags }}) - # Temporarily disabled until the nightly build bug is resolved - if: (!cancelled() && false) + if: (!cancelled()) strategy: matrix: flags: ["--all-features", "--no-default-features"] diff --git a/.github/workflows/_vercel_deploy.yml b/.github/workflows/_vercel_deploy.yml index 2a8d9d4dcba..47f9d854598 100644 --- a/.github/workflows/_vercel_deploy.yml +++ b/.github/workflows/_vercel_deploy.yml @@ -43,7 +43,7 @@ jobs: explorer-prod: name: Vercel Explorer Production - if: inputs.isDevelop && inputs.isExplorer + if: inputs.isDevelop uses: ./.github/workflows/apps-explorer.deploy.yml secrets: inherit with: @@ -59,7 +59,7 @@ jobs: ui-kit-prod: name: Vercel UI Kit Preview - if: inputs.isDevelop && inputs.isAppsUiKit + if: inputs.isDevelop uses: ./.github/workflows/apps-ui-kit.deploy.yml secrets: inherit with: @@ -75,7 +75,7 @@ jobs: wallet-dashboard-prod: name: Vercel Wallet Dashboard Production - if: inputs.isDevelop && inputs.isWalletDashboard + if: inputs.isDevelop uses: ./.github/workflows/apps-wallet-dashboard.deploy.yml secrets: inherit with: @@ -91,7 +91,7 @@ jobs: apps-backend-prod: name: Vercel apps-backend Production - if: inputs.isDevelop && inputs.isAppsBackend + if: inputs.isDevelop uses: ./.github/workflows/apps-backend.deploy.yml secrets: inherit with: diff --git a/.gitignore b/.gitignore index 17c1974647f..642158476ae 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ Move.lock !crates/iota-framework/packages/move-stdlib/Move.lock !crates/iota-framework/packages/iota-framework/Move.lock !crates/iota-framework/packages/iota-system/Move.lock -!crates/iota-framework/packages/deepbook/Move.lock !crates/iota-framework/packages/stardust/Move.lock !crates/iota-framework/packages/timelock/Move.lock .trace diff --git a/Cargo.lock b/Cargo.lock index 8627492edc9..c2fd51fc912 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1085,9 +1085,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd82dba44d209fddb11c190e0a94b78651f95299598e472215667417a03ff1d" +checksum = "2f95446d919226d587817a7d21379e6eb099b97b45110a7f272a444ca5c54070" dependencies = [ "aws-lc-sys", "mirai-annotations", @@ -1097,9 +1097,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.22.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7a4168111d7eb622a31b214057b8509c0a7e1794f44c546d742330dc793972" +checksum = "234314bd569802ec87011d653d6815c6d7b9ffb969e9fee5b8b20ef860e8dce9" dependencies = [ "bindgen 0.69.5", "cc", @@ -1858,7 +1858,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -5743,6 +5743,7 @@ dependencies = [ "move-analyzer", "move-binary-format", "move-bytecode-verifier-meter", + "move-cli", "move-command-line-common", "move-core-types", "move-package", @@ -15100,22 +15101,23 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2 1.0.86", "prost-build", + "prost-types", "quote 1.0.37", "syn 2.0.77", ] [[package]] name = "tonic-health" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0a34e6f706bae26b2b490e1da5c3f6a6ff87cae442bcbc7c881bab9631b5a7" +checksum = "1eaf34ddb812120f5c601162d5429933c9b527d901ab0e7f930d3147e33a09b2" dependencies = [ "async-stream", "prost", diff --git a/apps/explorer/src/components/IotaTokenCard.tsx b/apps/explorer/src/components/IotaTokenCard.tsx index 05720a0bd28..19bb5fa8286 100644 --- a/apps/explorer/src/components/IotaTokenCard.tsx +++ b/apps/explorer/src/components/IotaTokenCard.tsx @@ -4,8 +4,9 @@ import { Panel } from '@iota/apps-ui-kit'; import { COIN_GECKO_IOTA_URL, useIotaCoinData } from '@iota/core'; -import { IotaLogoMark } from '@iota/ui-icons'; -import { ButtonOrLink } from '~/components/ui'; +import { ButtonOrLink, ImageIconSize } from '~/components/ui'; +import { CoinIcon } from './owned-coins'; +import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; export function IotaTokenCard(): JSX.Element { const { data } = useIotaCoinData(); @@ -22,8 +23,8 @@ export function IotaTokenCard(): JSX.Element {
-
- +
+
diff --git a/apps/explorer/src/components/activity/EpochsActivityTable.tsx b/apps/explorer/src/components/activity/EpochsActivityTable.tsx index 4974e0c26ac..d3f50c0ad5b 100644 --- a/apps/explorer/src/components/activity/EpochsActivityTable.tsx +++ b/apps/explorer/src/components/activity/EpochsActivityTable.tsx @@ -2,13 +2,13 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { useIotaClientQuery, useIotaClient, useIotaClientInfiniteQuery } from '@iota/dapp-kit'; import { Warning } from '@iota/ui-icons'; import { useQuery } from '@tanstack/react-query'; import { useState } from 'react'; - import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateEpochsTableColumns } from '~/lib/ui'; import { numberSuffix } from '~/lib/utils'; @@ -71,29 +71,26 @@ export function EpochsActivityTable({ data={data.data} columns={tableColumns} totalLabel={count ? `${numberSuffix(Number(count))} Total` : '-'} - viewAll={!disablePagination ? '/recent?tab=epochs' : undefined} + viewAll="/recent?tab=epochs" paginationOptions={!disablePagination ? pagination : undefined} + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} -
-
); } diff --git a/apps/explorer/src/components/activity/TransactionsActivityTable.tsx b/apps/explorer/src/components/activity/TransactionsActivityTable.tsx index 6407314dadc..ac46b7e9dc2 100644 --- a/apps/explorer/src/components/activity/TransactionsActivityTable.tsx +++ b/apps/explorer/src/components/activity/TransactionsActivityTable.tsx @@ -5,16 +5,16 @@ import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useRef, useState } from 'react'; - import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_TRANSACTIONS_LIMIT, useGetTransactionBlocks, } from '~/hooks/useGetTransactionBlocks'; import { numberSuffix } from '~/lib/utils'; -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { generateTransactionsTableColumns } from '~/lib/ui'; import { Warning } from '@iota/ui-icons'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; interface TransactionsActivityTableProps { disablePagination?: boolean; @@ -76,27 +76,24 @@ export function TransactionsActivityTable({ totalLabel={count ? `${numberSuffix(Number(count))} Total` : '-'} viewAll="/recent" paginationOptions={!disablePagination ? pagination : undefined} + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} - - ); diff --git a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx index 5f045ddefdc..46baed3dd09 100644 --- a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx +++ b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx @@ -2,12 +2,13 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { useIotaClientQuery } from '@iota/dapp-kit'; import { Warning } from '@iota/ui-icons'; import { useMemo, useState } from 'react'; import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_CHECKPOINTS_LIMIT, useGetCheckpoints } from '~/hooks/useGetCheckpoints'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateCheckpointsTableColumns } from '~/lib/ui'; import { numberSuffix } from '~/lib/utils'; @@ -81,26 +82,24 @@ export function CheckpointsTable({ } : undefined } + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} - - ); } diff --git a/apps/explorer/src/components/owned-coins/CoinIcon.tsx b/apps/explorer/src/components/owned-coins/CoinIcon.tsx index db9c296e83b..a0263d92afe 100644 --- a/apps/explorer/src/components/owned-coins/CoinIcon.tsx +++ b/apps/explorer/src/components/owned-coins/CoinIcon.tsx @@ -3,69 +3,43 @@ // SPDX-License-Identifier: Apache-2.0 import { useCoinMetadata } from '@iota/core'; -import { IotaLogoMark as Iota, Unstake } from '@iota/ui-icons'; +import { IotaLogoMark } from '@iota/ui-icons'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import { cva, type VariantProps } from 'class-variance-authority'; +import { cx } from 'class-variance-authority'; +import { ImageIcon, ImageIconSize } from '../ui'; -import { ImageIcon } from '~/components/ui'; - -const imageStyle = cva(['flex rounded-2xl'], { - variants: { - size: { - sm: 'w-6 h-6', - md: 'w-7.5 h-7.5', - lg: 'md:w-10 md:h-10 w-8 h-8', - xl: 'md:w-31.5 md:h-31.5 w-16 h-16 ', - }, - }, - defaultVariants: { - size: 'md', - }, -}); - -function IotaCoin(): JSX.Element { - return ( - - ); -} - -interface NonIotaCoinProps extends VariantProps { +interface NonIotaCoinProps { coinType: string; + size?: ImageIconSize; + rounded?: boolean; } -function NonIotaCoin({ coinType, ...styleProps }: NonIotaCoinProps): JSX.Element { +function NonIotaCoin({ coinType, size = ImageIconSize.Full, rounded }: NonIotaCoinProps) { const { data: coinMeta } = useCoinMetadata(coinType); return ( -
- {coinMeta?.iconUrl ? ( - - ) : ( -
- -
- )} +
+
); } - -interface CoinIconProps extends VariantProps { +export interface CoinIconProps { coinType: string; + size?: ImageIconSize; + rounded?: boolean; } -export function CoinIcon({ coinType, ...styleProps }: CoinIconProps): JSX.Element { - return ( -
- {coinType === IOTA_TYPE_ARG ? ( - - ) : ( - - )} +export function CoinIcon({ coinType, size = ImageIconSize.Full, rounded }: CoinIconProps) { + return coinType === IOTA_TYPE_ARG ? ( +
+
+ ) : ( + ); } diff --git a/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx b/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx index 59f3899aed5..5f072935dcb 100644 --- a/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx +++ b/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx @@ -19,6 +19,7 @@ import { ImageType, } from '@iota/apps-ui-kit'; import { ArrowUp, RecognizedBadge } from '@iota/ui-icons'; +import { ImageIconSize } from '../ui'; type OwnedCoinViewProps = { coin: CoinBalanceVerified; @@ -45,8 +46,8 @@ export default function OwnedCoinView({ coin, id }: OwnedCoinViewProps): JSX.Ele > setAreCoinDetailsOpen((prev) => !prev)}> -
- +
+
diff --git a/apps/explorer/src/components/owned-coins/OwnedCoins.tsx b/apps/explorer/src/components/owned-coins/OwnedCoins.tsx index f84956ee770..0a52ca0d270 100644 --- a/apps/explorer/src/components/owned-coins/OwnedCoins.tsx +++ b/apps/explorer/src/components/owned-coins/OwnedCoins.tsx @@ -25,6 +25,7 @@ import { Title, } from '@iota/apps-ui-kit'; import { Pagination } from '../ui'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; export type CoinBalanceVerified = CoinBalance & { isRecognized?: boolean; @@ -197,11 +198,10 @@ export function OwnedCoins({ id }: OwnerCoinsProps): JSX.Element { ({ + options={PAGE_SIZES_RANGE_10_50.map((size) => ({ label: `${size} / page`, id: size.toString(), }))} diff --git a/apps/explorer/src/components/ui/ImageIcon.tsx b/apps/explorer/src/components/ui/ImageIcon.tsx index 05ae7adafe5..0366a9c741a 100644 --- a/apps/explorer/src/components/ui/ImageIcon.tsx +++ b/apps/explorer/src/components/ui/ImageIcon.tsx @@ -2,65 +2,71 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { cva, type VariantProps } from 'class-variance-authority'; import { useState } from 'react'; +import cn from 'clsx'; -const imageStyle = cva(['text-white capitalize overflow-hidden bg-gray-40'], { - variants: { - size: { - sm: 'w-6 h-6 font-medium text-subtitleSmallExtra', - md: 'w-8 h-8 text-label-lg', - lg: 'md:w-10 md:h-10 w-8 h-8', - xl: 'md:w-31.5 md:h-31.5 w-16 h-16 font-medium text-heading4 md:text-iconTextLarge', - }, - circle: { - true: 'rounded-full', - false: 'rounded-md', - }, - }, - - defaultVariants: { - circle: false, - size: 'md', - }, -}); +export enum ImageIconSize { + Small = 'w-5 h-5', + Medium = 'w-8 h-8', + Large = 'w-10 h-10', + Full = 'w-full h-full', +} -export interface ImageIconProps extends VariantProps { - src?: string | null; +export interface ImageIconProps { + src: string | null | undefined; label: string; fallback: string; alt?: string; + rounded?: boolean; + size?: ImageIconSize; } -interface FallBackAvatarProps { - fallback: string; -} - -function FallBackAvatar({ fallback }: FallBackAvatarProps): JSX.Element { +function FallBackAvatar({ + str, + rounded, + size = ImageIconSize.Large, +}: { + str: string; + rounded?: boolean; + size?: ImageIconSize; +}) { + function generateTextSize(size: ImageIconSize) { + switch (size) { + case ImageIconSize.Small: + return 'text-label-sm'; + case ImageIconSize.Medium: + return 'text-label-md'; + case ImageIconSize.Large: + return 'text-title-lg'; + case ImageIconSize.Full: + return 'text-display-lg'; + } + } return ( -
- {fallback?.slice(0, 2)} +
+ {str?.slice(0, 2)}
); } -export function ImageIcon({ - src, - label, - alt = label, - fallback, - ...styleProps -}: ImageIconProps): JSX.Element { +export function ImageIcon({ src, label, alt = label, fallback, rounded, size }: ImageIconProps) { const [error, setError] = useState(false); return ( -
+
{error || !src ? ( - + ) : ( {alt} setError(true)} /> )} diff --git a/apps/explorer/src/components/ui/TableCard.tsx b/apps/explorer/src/components/ui/TableCard.tsx index 372ecc0cb36..0804e7755b8 100644 --- a/apps/explorer/src/components/ui/TableCard.tsx +++ b/apps/explorer/src/components/ui/TableCard.tsx @@ -21,7 +21,7 @@ import { useReactTable, } from '@tanstack/react-table'; import clsx from 'clsx'; -import { Fragment, useState } from 'react'; +import { Fragment, type ReactNode, useState } from 'react'; import { Link } from './Link'; export interface TableCardProps { @@ -34,6 +34,7 @@ export interface TableCardProps { paginationOptions?: TablePaginationOptions; totalLabel?: string; viewAll?: string; + pageSizeSelector?: ReactNode; } export function TableCard({ @@ -46,6 +47,7 @@ export function TableCard({ paginationOptions, totalLabel, viewAll, + pageSizeSelector, }: TableCardProps): JSX.Element { const [sorting, setSorting] = useState(defaultSorting || []); @@ -66,7 +68,7 @@ export function TableCard({ }); return ( -
+
row.index)} paginationOptions={paginationOptions} @@ -78,6 +80,7 @@ export function TableCard({ ) : undefined } + pageSizeSelector={pageSizeSelector} > {table.getHeaderGroups().map((headerGroup) => ( diff --git a/apps/explorer/src/components/validator/ValidatorMeta.tsx b/apps/explorer/src/components/validator/ValidatorMeta.tsx index 489f906780b..386048bdebd 100644 --- a/apps/explorer/src/components/validator/ValidatorMeta.tsx +++ b/apps/explorer/src/components/validator/ValidatorMeta.tsx @@ -6,7 +6,7 @@ import { Badge, BadgeType, KeyValueInfo, Panel } from '@iota/apps-ui-kit'; import { type IotaValidatorSummary } from '@iota/iota-sdk/client'; import toast from 'react-hot-toast'; import { ArrowTopRight } from '@iota/ui-icons'; -import { AddressLink, ImageIcon } from '~/components/ui'; +import { AddressLink, ImageIcon, ImageIconSize } from '~/components/ui'; type ValidatorMetaProps = { validatorData: IotaValidatorSummary; @@ -28,12 +28,14 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps): JSX.Elemen
- +
+ +
diff --git a/apps/explorer/src/lib/constants/index.ts b/apps/explorer/src/lib/constants/index.ts index 5c33042b10e..99b4cfa783a 100644 --- a/apps/explorer/src/lib/constants/index.ts +++ b/apps/explorer/src/lib/constants/index.ts @@ -3,3 +3,4 @@ export * from './footer.constants'; export * from './validator.constants'; +export * from './pageSize.constants'; diff --git a/apps/explorer/src/lib/constants/pageSize.constants.ts b/apps/explorer/src/lib/constants/pageSize.constants.ts new file mode 100644 index 00000000000..126a9ed0ee2 --- /dev/null +++ b/apps/explorer/src/lib/constants/pageSize.constants.ts @@ -0,0 +1,5 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export const PAGE_SIZES_RANGE_10_50 = [10, 20, 30, 40, 50]; +export const PAGE_SIZES_RANGE_20_60 = [20, 40, 60]; diff --git a/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx b/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx index e175ba717d1..b053b889695 100644 --- a/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx +++ b/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx @@ -4,11 +4,11 @@ import { Badge, BadgeType, TableCellBase, TableCellText } from '@iota/apps-ui-kit'; import type { ColumnDef } from '@tanstack/react-table'; import { type ApyByValidator, formatPercentageDisplay } from '@iota/core'; - import { ampli, getValidatorMoveEvent, VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/lib'; -import { StakeColumn, ValidatorLink, ImageIcon } from '~/components'; +import { StakeColumn } from '~/components'; import type { IotaEvent, IotaValidatorSummary } from '@iota/iota-sdk/dist/cjs/client'; import clsx from 'clsx'; +import { ImageIcon, ImageIconSize, ValidatorLink } from '~/components/ui'; interface generateValidatorsTableColumnsArgs { atRiskValidators: [string, string][]; @@ -41,7 +41,7 @@ function ValidatorWithImage({
diff --git a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx index 029eb40c032..f5370c56255 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx @@ -2,13 +2,14 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { DropdownPosition, Select, SelectSize } from '@iota/apps-ui-kit'; import { useState } from 'react'; - -import { Pagination, PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; +import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_TRANSACTIONS_LIMIT, useGetTransactionBlocks, } from '~/hooks/useGetTransactionBlocks'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateTransactionsTableColumns } from '~/lib/ui'; export function CheckpointTransactionBlocks({ id }: { id: string }): JSX.Element { @@ -34,24 +35,28 @@ export function CheckpointTransactionBlocks({ id }: { id: string }): JSX.Element /> ) : (
- + ({ + label: `${size} / page`, + id: size.toString(), + }))} + onValueChange={(value) => { + setLimit(Number(value)); + pagination.onFirst(); + }} + size={SelectSize.Small} + /> + } + />
)} -
- - -
); } diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx index 60c63f0675c..f532c0bcecc 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx @@ -23,7 +23,7 @@ import { } from '@iota/core'; import { RecognizedBadge } from '@iota/ui-icons'; import { useMemo } from 'react'; -import { CoinIcon } from '~/components'; +import { CoinIcon, ImageIconSize } from '~/components'; import { AddressLink, CollapsibleCard } from '~/components/ui'; import { BREAK_POINT, useMediaQuery } from '~/hooks'; @@ -49,7 +49,7 @@ function BalanceChangeEntry({ change }: { change: BalanceChange }): JSX.Element
- + = { [CardType.Default]: 'border border-transparent', [CardType.Outlined]: 'border border-shader-neutral-light-8 dark:border-shader-primary-dark-8 p-xs', - [CardType.Filled]: 'border border-transparent bg-shader-neutral-light-8 p-xs', + [CardType.Filled]: 'border border-transparent bg-neutral-96 dark:bg-neutral-10 p-xs', }; diff --git a/apps/ui-kit/src/lib/components/organisms/dialog/Dialog.tsx b/apps/ui-kit/src/lib/components/organisms/dialog/Dialog.tsx index d36846dc852..ddd77e87df7 100644 --- a/apps/ui-kit/src/lib/components/organisms/dialog/Dialog.tsx +++ b/apps/ui-kit/src/lib/components/organisms/dialog/Dialog.tsx @@ -7,6 +7,7 @@ import cx from 'classnames'; import * as React from 'react'; import { Close } from '@iota/ui-icons'; import { useEffect, useState } from 'react'; +import { DialogPosition } from './dialog.enums'; const Dialog = RadixDialog.Root; const DialogTrigger = RadixDialog.Trigger; @@ -35,34 +36,55 @@ const DialogContent = React.forwardRef< React.ComponentPropsWithoutRef & { containerId?: string; showCloseOnOverlay?: boolean; + position?: DialogPosition; } ->(({ className, containerId, showCloseOnOverlay, children, ...props }, ref) => { - const [containerElement, setContainerElement] = useState(undefined); +>( + ( + { + className, + containerId, + showCloseOnOverlay, + children, + position = DialogPosition.Center, + ...props + }, + ref, + ) => { + const [containerElement, setContainerElement] = useState( + undefined, + ); - useEffect(() => { - // This ensures document.getElementById is called in the client-side environment only. - // note. containerElement cant be null - const element = containerId ? document.getElementById(containerId) : undefined; - setContainerElement(element ?? undefined); - }, [containerId]); - - return ( - - - - - - - - {children} - - - ); -}); + useEffect(() => { + // This ensures document.getElementById is called in the client-side environment only. + // note. containerElement cant be null + const element = containerId ? document.getElementById(containerId) : undefined; + setContainerElement(element ?? undefined); + }, [containerId]); + const positionClass = + position === DialogPosition.Right + ? 'right-0 h-screen top-0 w-full max-w-[500px]' + : 'max-h-[60vh] left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl w-80 max-w-[85vw]'; + return ( + + + + + + + + {children} + + + ); + }, +); DialogContent.displayName = RadixDialog.Content.displayName; const DialogTitle = React.forwardRef< diff --git a/apps/ui-kit/src/lib/components/organisms/dialog/dialog.enums.ts b/apps/ui-kit/src/lib/components/organisms/dialog/dialog.enums.ts new file mode 100644 index 00000000000..053d6ca0ee7 --- /dev/null +++ b/apps/ui-kit/src/lib/components/organisms/dialog/dialog.enums.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export enum DialogPosition { + Center = 'center', + Right = 'right', +} diff --git a/apps/ui-kit/src/lib/components/organisms/dialog/index.ts b/apps/ui-kit/src/lib/components/organisms/dialog/index.ts index e666b2e9217..42965e76f7c 100644 --- a/apps/ui-kit/src/lib/components/organisms/dialog/index.ts +++ b/apps/ui-kit/src/lib/components/organisms/dialog/index.ts @@ -2,3 +2,4 @@ // SPDX-License-Identifier: Apache-2.0 export * from './Dialog'; +export * from './dialog.enums'; diff --git a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx index 36d567330f7..a848b0c9937 100644 --- a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx +++ b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx @@ -56,7 +56,7 @@ export type TableProps = { */ paginationOptions?: TablePaginationOptions; /** - * The action component.. + * The action component. */ action?: ReactNode; /** @@ -71,6 +71,10 @@ export type TableProps = { * Numeric indexes of all the rows. */ rowIndexes: number[]; + /** + * The page size selector component. + */ + pageSizeSelector?: ReactNode; }; export function Table({ @@ -80,6 +84,7 @@ export function Table({ selectedRowIndexes = new Set(), rowIndexes, children, + pageSizeSelector, }: PropsWithChildren): JSX.Element { return ( @@ -88,8 +93,10 @@ export function Table({
{children}
{paginationOptions && ( @@ -122,14 +129,19 @@ export function Table({ disabled={!paginationOptions.hasLast} onClick={paginationOptions.onLast} /> + {action}
)} - {action} - {supportingLabel && ( - - {supportingLabel} - - )} + {supportingLabel || pageSizeSelector ? ( +
+ {supportingLabel && ( + + {supportingLabel} + + )} + {pageSizeSelector &&
{pageSizeSelector}
} +
+ ) : null}
diff --git a/apps/ui-kit/src/storybook/stories/organisms/Dialog.stories.tsx b/apps/ui-kit/src/storybook/stories/organisms/Dialog.stories.tsx index 39c4f0da22d..d3e3317c39f 100644 --- a/apps/ui-kit/src/storybook/stories/organisms/Dialog.stories.tsx +++ b/apps/ui-kit/src/storybook/stories/organisms/Dialog.stories.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ButtonSize } from '@/lib/components'; +import { ButtonSize, DialogPosition } from '@/lib/components'; import type { Meta, StoryObj } from '@storybook/react'; @@ -54,3 +54,50 @@ export default meta; type Story = StoryObj; export const Default: Story = {}; + +export const RightDialog: Story = { + render: () => { + const [open, setOpen] = useState(false); + return ( +
+
+
+
+ + +
+ ); + }, +}; diff --git a/apps/wallet-dashboard/app/dashboard/activity/page.tsx b/apps/wallet-dashboard/app/(protected)/activity/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/activity/page.tsx rename to apps/wallet-dashboard/app/(protected)/activity/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx b/apps/wallet-dashboard/app/(protected)/assets/everything-else/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx rename to apps/wallet-dashboard/app/(protected)/assets/everything-else/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/assets/layout.tsx b/apps/wallet-dashboard/app/(protected)/assets/layout.tsx similarity index 74% rename from apps/wallet-dashboard/app/dashboard/assets/layout.tsx rename to apps/wallet-dashboard/app/(protected)/assets/layout.tsx index 2ace7b31545..b579dfae131 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/layout.tsx +++ b/apps/wallet-dashboard/app/(protected)/assets/layout.tsx @@ -3,12 +3,13 @@ 'use client'; import { RouteLink } from '@/components/index'; +import { ASSETS_ROUTE } from '@/lib/constants/routes.constants'; import React, { type PropsWithChildren } from 'react'; function AssetsLayout({ children }: PropsWithChildren): JSX.Element { const routes = [ - { title: 'Visual Assets', path: '/dashboard/assets/visual-assets' }, - { title: 'Everything Else', path: '/dashboard/assets/everything-else' }, + { title: 'Visual Assets', path: ASSETS_ROUTE.path + '/visual-assets' }, + { title: 'Everything Else', path: ASSETS_ROUTE.path + '/everything-else' }, ]; return ( diff --git a/apps/wallet-dashboard/app/dashboard/assets/page.tsx b/apps/wallet-dashboard/app/(protected)/assets/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/assets/page.tsx rename to apps/wallet-dashboard/app/(protected)/assets/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/[objectId]/page.tsx b/apps/wallet-dashboard/app/(protected)/assets/visual-assets/[objectId]/page.tsx similarity index 90% rename from apps/wallet-dashboard/app/dashboard/assets/visual-assets/[objectId]/page.tsx rename to apps/wallet-dashboard/app/(protected)/assets/visual-assets/[objectId]/page.tsx index 587d2ccce03..e9fe1e9146c 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/[objectId]/page.tsx +++ b/apps/wallet-dashboard/app/(protected)/assets/visual-assets/[objectId]/page.tsx @@ -9,6 +9,7 @@ import { AssetCard, Button, RouteLink, SendAssetPopup } from '@/components'; import { isAssetTransferable, useGetObject } from '@iota/core'; import { usePopups } from '@/hooks'; import { useCurrentAccount } from '@iota/dapp-kit'; +import { ASSETS_ROUTE } from '@/lib/constants/routes.constants'; const VisualAssetDetailPage = () => { const params = useParams(); @@ -28,7 +29,7 @@ const VisualAssetDetailPage = () => { return (
- + {asset?.data ? ( ) : ( diff --git a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx b/apps/wallet-dashboard/app/(protected)/assets/visual-assets/page.tsx similarity index 92% rename from apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx rename to apps/wallet-dashboard/app/(protected)/assets/visual-assets/page.tsx index fe08f79fdfd..2819bb4bfd3 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx +++ b/apps/wallet-dashboard/app/(protected)/assets/visual-assets/page.tsx @@ -9,6 +9,7 @@ import { AssetCard, VirtualList } from '@/components/index'; import { useCurrentAccount } from '@iota/dapp-kit'; import { hasDisplayData, useGetOwnedObjects } from '@iota/core'; import { useRouter } from 'next/navigation'; +import { ASSETS_ROUTE } from '@/lib/constants/routes.constants'; function VisualAssetsPage(): JSX.Element { const account = useCurrentAccount(); @@ -29,7 +30,7 @@ function VisualAssetsPage(): JSX.Element { const virtualItem = (asset: IotaObjectData): JSX.Element => ; const handleClick = (objectId: string) => { - router.push(`/dashboard/assets/visual-assets/${objectId}`); + router.push(ASSETS_ROUTE.path + `/visual-assets/${objectId}`); }; return ( diff --git a/apps/wallet-dashboard/app/(protected)/components/index.ts b/apps/wallet-dashboard/app/(protected)/components/index.ts new file mode 100644 index 00000000000..b4406b11a68 --- /dev/null +++ b/apps/wallet-dashboard/app/(protected)/components/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from './sidebar/Sidebar'; diff --git a/apps/wallet-dashboard/app/(protected)/components/sidebar/Sidebar.tsx b/apps/wallet-dashboard/app/(protected)/components/sidebar/Sidebar.tsx new file mode 100644 index 00000000000..0f49225192d --- /dev/null +++ b/apps/wallet-dashboard/app/(protected)/components/sidebar/Sidebar.tsx @@ -0,0 +1,19 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { PROTECTED_ROUTES } from '@/lib/constants/routes.constants'; +import { IotaLogoMark } from '@iota/ui-icons'; +import { SidebarItem } from './SidebarItem'; + +export function Sidebar() { + return ( + + ); +} diff --git a/apps/wallet-dashboard/app/(protected)/components/sidebar/SidebarItem.tsx b/apps/wallet-dashboard/app/(protected)/components/sidebar/SidebarItem.tsx new file mode 100644 index 00000000000..e81e6da5b66 --- /dev/null +++ b/apps/wallet-dashboard/app/(protected)/components/sidebar/SidebarItem.tsx @@ -0,0 +1,22 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +'use client'; + +import type { ProtectedRoute } from '@/lib/interfaces'; +import { NavbarItem, Tooltip, TooltipPosition } from '@iota/apps-ui-kit'; +import { usePathname } from 'next/navigation'; +import Link from 'next/link'; + +export function SidebarItem({ icon, title, path }: ProtectedRoute) { + const pathname = usePathname(); + const RouteIcon = icon; + const isActive = pathname === path; + return ( + + + } /> + + + ); +} diff --git a/apps/wallet-dashboard/app/(protected)/components/top-nav/TopNav.tsx b/apps/wallet-dashboard/app/(protected)/components/top-nav/TopNav.tsx new file mode 100644 index 00000000000..8dd5f01ca2b --- /dev/null +++ b/apps/wallet-dashboard/app/(protected)/components/top-nav/TopNav.tsx @@ -0,0 +1,16 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { Badge, BadgeType, Button, ButtonType } from '@iota/apps-ui-kit'; +import { ConnectButton } from '@iota/dapp-kit'; +import { Settings } from '@iota/ui-icons'; + +export function TopNav() { + return ( +
+ + +
+ ); +} diff --git a/apps/wallet-dashboard/app/dashboard/home/page.tsx b/apps/wallet-dashboard/app/(protected)/home/page.tsx similarity index 93% rename from apps/wallet-dashboard/app/dashboard/home/page.tsx rename to apps/wallet-dashboard/app/(protected)/home/page.tsx index f862e2ffc03..53c3d8433b3 100644 --- a/apps/wallet-dashboard/app/dashboard/home/page.tsx +++ b/apps/wallet-dashboard/app/(protected)/home/page.tsx @@ -16,7 +16,7 @@ function HomeDashboardPage(): JSX.Element { }; return ( -
+

Connection status: {connectionStatus}

{connectionStatus === 'connected' && account && (
diff --git a/apps/wallet-dashboard/app/(protected)/layout.tsx b/apps/wallet-dashboard/app/(protected)/layout.tsx new file mode 100644 index 00000000000..18168a98870 --- /dev/null +++ b/apps/wallet-dashboard/app/(protected)/layout.tsx @@ -0,0 +1,55 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +'use client'; + +import { Notifications } from '@/components/index'; +import React, { useEffect, useState, type PropsWithChildren } from 'react'; +import { useCurrentAccount, useCurrentWallet } from '@iota/dapp-kit'; +import { Button } from '@iota/apps-ui-kit'; +import { redirect } from 'next/navigation'; +import { Sidebar } from './components'; +import { TopNav } from './components/top-nav/TopNav'; + +function DashboardLayout({ children }: PropsWithChildren): JSX.Element { + const [isDarkMode, setIsDarkMode] = useState(false); + const { connectionStatus } = useCurrentWallet(); + const account = useCurrentAccount(); + + const toggleDarkMode = () => { + setIsDarkMode(!isDarkMode); + if (isDarkMode) { + document.documentElement.classList.remove('dark'); + } else { + document.documentElement.classList.add('dark'); + } + }; + + useEffect(() => { + if (connectionStatus !== 'connected' && !account) { + redirect('/'); + } + }, [connectionStatus, account]); + + return ( +
+
+ +
+ +
+
+ +
+
{children}
+
+ +
+
+ + +
+ ); +} + +export default DashboardLayout; diff --git a/apps/wallet-dashboard/app/dashboard/migrations/page.tsx b/apps/wallet-dashboard/app/(protected)/migrations/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/migrations/page.tsx rename to apps/wallet-dashboard/app/(protected)/migrations/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/staking/page.tsx b/apps/wallet-dashboard/app/(protected)/staking/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/staking/page.tsx rename to apps/wallet-dashboard/app/(protected)/staking/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/vesting/page.tsx b/apps/wallet-dashboard/app/(protected)/vesting/page.tsx similarity index 100% rename from apps/wallet-dashboard/app/dashboard/vesting/page.tsx rename to apps/wallet-dashboard/app/(protected)/vesting/page.tsx diff --git a/apps/wallet-dashboard/app/dashboard/apps/page.tsx b/apps/wallet-dashboard/app/dashboard/apps/page.tsx deleted file mode 100644 index cb6c956a6a4..00000000000 --- a/apps/wallet-dashboard/app/dashboard/apps/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -'use client'; - -import { AppList } from '@/components'; - -function AppsPage(): JSX.Element { - return ( -
-

APPS

- -
- ); -} - -export default AppsPage; diff --git a/apps/wallet-dashboard/app/dashboard/layout.tsx b/apps/wallet-dashboard/app/dashboard/layout.tsx deleted file mode 100644 index 69c6a6da46a..00000000000 --- a/apps/wallet-dashboard/app/dashboard/layout.tsx +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 -'use client'; - -import { Notifications, RouteLink } from '@/components/index'; -import React, { useState, type PropsWithChildren } from 'react'; -import { ConnectButton } from '@iota/dapp-kit'; -import { Button } from '@iota/apps-ui-kit'; - -const routes = [ - { title: 'Home', path: '/dashboard/home' }, - { title: 'Assets', path: '/dashboard/assets' }, - { title: 'Staking', path: '/dashboard/staking' }, - { title: 'Apps', path: '/dashboard/apps' }, - { title: 'Activity', path: '/dashboard/activity' }, - { title: 'Migrations', path: '/dashboard/migrations' }, - { title: 'Vesting', path: '/dashboard/vesting' }, -]; - -function DashboardLayout({ children }: PropsWithChildren): JSX.Element { - const [isDarkMode, setIsDarkMode] = useState(false); - - const toggleDarkMode = () => { - setIsDarkMode(!isDarkMode); - if (isDarkMode) { - document.documentElement.classList.remove('dark'); - } else { - document.documentElement.classList.add('dark'); - } - }; - - // TODO: check if the wallet is connected and if not redirect to the welcome screen - return ( - <> -
- - {routes.map((route) => { - return ; - })} -
-
{children}
- - ); -} - -export default DashboardLayout; diff --git a/apps/wallet-dashboard/app/layout.tsx b/apps/wallet-dashboard/app/layout.tsx index badfa837057..dadbd552dbf 100644 --- a/apps/wallet-dashboard/app/layout.tsx +++ b/apps/wallet-dashboard/app/layout.tsx @@ -6,7 +6,7 @@ import { Inter } from 'next/font/google'; import './globals.css'; -import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; +import { IotaClientProvider, lightTheme, darkTheme, WalletProvider } from '@iota/dapp-kit'; import { getAllNetworks, getDefaultNetwork } from '@iota/iota-sdk/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; @@ -22,16 +22,27 @@ export default function RootLayout({ children: React.ReactNode; }>) { const [queryClient] = React.useState(() => new QueryClient()); + const bodyRef = React.useRef(null); const allNetworks = getAllNetworks(); const defaultNetwork = getDefaultNetwork(); return ( - + - + {children} diff --git a/apps/wallet-dashboard/app/page.tsx b/apps/wallet-dashboard/app/page.tsx new file mode 100644 index 00000000000..38001d4b184 --- /dev/null +++ b/apps/wallet-dashboard/app/page.tsx @@ -0,0 +1,62 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +'use client'; + +import { ConnectButton, useCurrentAccount, useCurrentWallet } from '@iota/dapp-kit'; +import { useEffect } from 'react'; +import { redirect } from 'next/navigation'; +import { IotaLogoWeb } from '@iota/ui-icons'; +import { HOMEPAGE_ROUTE } from '@/lib/constants/routes.constants'; + +function HomeDashboardPage(): JSX.Element { + const { connectionStatus } = useCurrentWallet(); + const account = useCurrentAccount(); + + const CURRENT_YEAR = new Date().getFullYear(); + + useEffect(() => { + if (connectionStatus === 'connected' && account) { + redirect(HOMEPAGE_ROUTE.path); + } + }, [connectionStatus, account]); + + return ( +
+
+ +
+
+ +
+
+ Welcome to +

IOTA Wallet

+ + Connecting you to the decentralized web and IOTA network + +
+
+ +
+
+
+ © IOTA Foundation {CURRENT_YEAR} +
+
+
+ ); +} + +export default HomeDashboardPage; diff --git a/apps/wallet-dashboard/components/Popup/Popups/SendAssetPopup.tsx b/apps/wallet-dashboard/components/Popup/Popups/SendAssetPopup.tsx index 305476e73f7..8dbcf912276 100644 --- a/apps/wallet-dashboard/components/Popup/Popups/SendAssetPopup.tsx +++ b/apps/wallet-dashboard/components/Popup/Popups/SendAssetPopup.tsx @@ -12,6 +12,7 @@ import { useRouter } from 'next/navigation'; import { useNotifications } from '@/hooks'; import { NotificationType } from '@/stores/notificationStore'; import { useCreateSendAssetTransaction } from '@/hooks'; +import { ASSETS_ROUTE } from '@/lib/constants/routes.constants'; interface SendAssetPopupProps { asset: IotaObjectData; @@ -48,7 +49,7 @@ export default function SendAssetPopup({ asset, onClose }: SendAssetPopupProps): function onSendAssetSuccess() { addNotification('Transfer transaction successful', NotificationType.Success); onClose?.(); - router.push('/dashboard/assets/visual-assets'); + router.push(ASSETS_ROUTE.path + '/visual-assets'); } function onSendAssetError() { diff --git a/apps/wallet-dashboard/lib/constants/routes.constants.ts b/apps/wallet-dashboard/lib/constants/routes.constants.ts new file mode 100644 index 00000000000..246be3eb40e --- /dev/null +++ b/apps/wallet-dashboard/lib/constants/routes.constants.ts @@ -0,0 +1,49 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import type { ProtectedRoute } from '../interfaces'; +import { ProtectedRouteTitle } from '../enums'; +import { Activity, Assets, Calendar, Home, Migration, Tokens } from '@iota/ui-icons'; + +export const HOMEPAGE_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Home, + path: '/home', + icon: Home, +}; + +export const ASSETS_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Assets, + path: '/assets', + icon: Assets, +}; + +export const STAKING_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Staking, + path: '/staking', + icon: Activity, +}; + +export const ACTIVITY_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Activity, + path: '/activity', + icon: Tokens, +}; +export const MIGRATIONS_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Migrations, + path: '/migrations', + icon: Calendar, +}; +export const VESTING_ROUTE: ProtectedRoute = { + title: ProtectedRouteTitle.Vesting, + path: '/vesting', + icon: Migration, +}; + +export const PROTECTED_ROUTES = [ + HOMEPAGE_ROUTE, + ASSETS_ROUTE, + STAKING_ROUTE, + ACTIVITY_ROUTE, + MIGRATIONS_ROUTE, + VESTING_ROUTE, +] as const satisfies ProtectedRoute[]; diff --git a/apps/wallet-dashboard/lib/enums/index.ts b/apps/wallet-dashboard/lib/enums/index.ts new file mode 100644 index 00000000000..a9ebb8b34ad --- /dev/null +++ b/apps/wallet-dashboard/lib/enums/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from './protectedRouteTitle.enum'; diff --git a/apps/wallet-dashboard/lib/enums/protectedRouteTitle.enum.ts b/apps/wallet-dashboard/lib/enums/protectedRouteTitle.enum.ts new file mode 100644 index 00000000000..a25fbd825a4 --- /dev/null +++ b/apps/wallet-dashboard/lib/enums/protectedRouteTitle.enum.ts @@ -0,0 +1,11 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export enum ProtectedRouteTitle { + Home = 'Home', + Assets = 'Assets', + Staking = 'Staking', + Activity = 'Activity', + Migrations = 'Migrations', + Vesting = 'Vesting', +} diff --git a/apps/wallet-dashboard/lib/interfaces/appRoute.interface.ts b/apps/wallet-dashboard/lib/interfaces/appRoute.interface.ts new file mode 100644 index 00000000000..c661dce5598 --- /dev/null +++ b/apps/wallet-dashboard/lib/interfaces/appRoute.interface.ts @@ -0,0 +1,8 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export interface ProtectedRoute { + title: string; + path: string; + icon: (props: React.SVGProps) => React.JSX.Element; +} diff --git a/apps/wallet-dashboard/lib/interfaces/index.ts b/apps/wallet-dashboard/lib/interfaces/index.ts index b00df15b193..eeab2cb4f5c 100644 --- a/apps/wallet-dashboard/lib/interfaces/index.ts +++ b/apps/wallet-dashboard/lib/interfaces/index.ts @@ -4,3 +4,4 @@ export * from './transactions.interface'; export * from './timelock.interface'; export * from './vesting.interface'; +export * from './appRoute.interface'; diff --git a/apps/wallet-dashboard/next.config.mjs b/apps/wallet-dashboard/next.config.mjs index e40a78b5e98..2727f8fcd80 100644 --- a/apps/wallet-dashboard/next.config.mjs +++ b/apps/wallet-dashboard/next.config.mjs @@ -5,11 +5,6 @@ const nextConfig = { async redirects() { return [ - { - source: '/', - destination: '/dashboard/home', - permanent: true, - }, { source: '/dashboard', destination: '/dashboard/home', diff --git a/apps/wallet-dashboard/package.json b/apps/wallet-dashboard/package.json index 1398daf9a87..6807f6fda94 100644 --- a/apps/wallet-dashboard/package.json +++ b/apps/wallet-dashboard/package.json @@ -22,6 +22,7 @@ "@iota/ui-icons": "workspace:*", "@tanstack/react-query": "^5.50.1", "@tanstack/react-virtual": "^3.5.0", + "clsx": "^2.1.1", "next": "14.2.10", "react": "^18.3.1", "zustand": "^4.4.1" diff --git a/apps/wallet-dashboard/tsconfig.json b/apps/wallet-dashboard/tsconfig.json index 2e42283cc00..d452a8afa13 100644 --- a/apps/wallet-dashboard/tsconfig.json +++ b/apps/wallet-dashboard/tsconfig.json @@ -20,6 +20,7 @@ ], "paths": { "@/*": ["./*"], + "@/lib/*": ["./lib/*"], "@/app/*": ["./app/*"], "@/components/*": ["./components/*"], "@/hooks/*": ["./hooks/*"], diff --git a/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx b/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx index 6005c4e3b55..a068e239e8e 100644 --- a/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx +++ b/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx @@ -6,7 +6,7 @@ import { useCopyToClipboard } from '../../hooks/useCopyToClipboard'; import { type SerializedUIAccount } from '_src/background/accounts/Account'; import { useBalance, useFormatCoin } from '@iota/core'; import { Copy } from '@iota/ui-icons'; -import { ButtonUnstyled } from '@iota/apps-ui-kit'; +import { Panel, ButtonUnstyled } from '@iota/apps-ui-kit'; interface AccountBalanceItemProps { account: SerializedUIAccount; @@ -23,23 +23,24 @@ export function AccountBalanceItem({ account }: AccountBalanceItemProps): JSX.El const totalBalance = balance?.totalBalance || '0'; const coinType = balance?.coinType; const [formatted, symbol] = useFormatCoin(BigInt(totalBalance), coinType); - return ( -
-
-
- {formatAddress(account.address)} -
- - - + +
+
+
+ {formatAddress(account.address)} +
+ + + +
-
- - {formatted} {symbol} - + + {formatted} {symbol} + +
-
+ ); } diff --git a/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx b/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx index 94fa1ac49f7..5ae321fa9bf 100644 --- a/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx +++ b/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx @@ -5,9 +5,7 @@ import { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; import { z } from 'zod'; - import { CheckboxField } from '../../shared/forms/CheckboxField'; -import FormField from '../../shared/forms/FormField'; import { SelectField } from '../../shared/forms/SelectField'; import { Input, InputType, type SelectOption } from '@iota/apps-ui-kit'; @@ -59,24 +57,23 @@ export function AutoLockSelector({ disabled }: AutoLockSelectorProps) { label="Auto-lock after I'm inactive for" disabled={disabled} /> - -
-
- -
-
- -
+
+
+ +
+
+
- +
); } diff --git a/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx b/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx index 1fcdf4fc405..ef3d2620d80 100644 --- a/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx +++ b/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx @@ -124,7 +124,7 @@ export function ImportRecoveryPhraseForm({ })}
-
+
{touchedFields.recoveryPhrase && errors.recoveryPhrase && (
- +
+
- } + icon={} > ); } diff --git a/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx b/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx index 63b6388e8e5..b30ac753ffc 100644 --- a/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx +++ b/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx @@ -11,6 +11,7 @@ import { useAccountByAddress } from '../../hooks/useAccountByAddress'; import { useSigner } from '../../hooks/useSigner'; import { respondToTransactionRequest } from '../../redux/slices/transaction-requests'; import { PageMainLayoutTitle } from '../../shared/page-main-layout/PageMainLayoutTitle'; +import { Panel } from '@iota/apps-ui-kit'; export interface SignMessageRequestProps { request: SignPersonalMessageApprovalRequest; @@ -47,14 +48,16 @@ export function SignMessageRequest({ request }: SignMessageRequestProps) { checkAccountLock > -
+
Message You Are Signing
-
-
- {message} + +
+
+ {message} +
-
+ ); } diff --git a/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx b/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx index 001d31ab4ee..064184e9f31 100644 --- a/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx +++ b/apps/wallet/src/ui/app/pages/home/tokens/TokensDetails.tsx @@ -195,10 +195,10 @@ function TokenDetails({ coinType }: TokenDetailsProps) { ) : (
-
+
{!accountHasIota ? ( -
-
+
+
{isMainnet ? 'Start by buying IOTA' diff --git a/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx b/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx index c8def20901b..111017d0bb0 100644 --- a/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx +++ b/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx @@ -19,7 +19,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; import { toast } from 'react-hot-toast'; import { Navigate, useNavigate, useSearchParams } from 'react-router-dom'; - import { PreviewTransfer } from './PreviewTransfer'; import { SendTokenForm, type SubmitProps } from './SendTokenForm'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; @@ -218,20 +217,14 @@ function CoinSelector({ ); } -function CoinSelectOption({ - coin: { coinType, totalBalance }, - size, -}: { - coin: CoinBalance; - size?: ImageIconSize; -}) { +function CoinSelectOption({ coin: { coinType, totalBalance } }: { coin: CoinBalance }) { const [formatted, symbol, { data: coinMeta }] = useFormatCoin(totalBalance, coinType); const isIota = coinType === IOTA_TYPE_ARG; return (
-
+
diff --git a/apps/wallet/src/ui/app/shared/forms/CheckboxField.tsx b/apps/wallet/src/ui/app/shared/forms/CheckboxField.tsx index 670748de62f..a9e5b4ea3aa 100644 --- a/apps/wallet/src/ui/app/shared/forms/CheckboxField.tsx +++ b/apps/wallet/src/ui/app/shared/forms/CheckboxField.tsx @@ -4,7 +4,6 @@ import { forwardRef, type ComponentProps, type ReactNode } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import FormField from './FormField'; import { Checkbox } from '@iota/apps-ui-kit'; type CheckboxFieldProps = { @@ -20,19 +19,17 @@ export const CheckboxField = forwardRef( control={control} name={name} render={({ field: { onChange, name, value } }) => ( - -
- -
-
+
+ +
)} /> ); diff --git a/apps/wallet/src/ui/app/shared/forms/FormField.tsx b/apps/wallet/src/ui/app/shared/forms/FormField.tsx deleted file mode 100644 index 3f8964f132f..00000000000 --- a/apps/wallet/src/ui/app/shared/forms/FormField.tsx +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { type ReactNode } from 'react'; - -interface FormFieldProps { - name: string; - children: ReactNode; -} - -export function FormField({ children }: FormFieldProps) { - return
{children}
; -} - -export default FormField; diff --git a/apps/wallet/src/ui/app/shared/forms/TextAreaField.tsx b/apps/wallet/src/ui/app/shared/forms/TextAreaField.tsx index a6a15be1035..a724cfaa1d1 100644 --- a/apps/wallet/src/ui/app/shared/forms/TextAreaField.tsx +++ b/apps/wallet/src/ui/app/shared/forms/TextAreaField.tsx @@ -3,8 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 import { forwardRef, type ComponentProps, type ReactNode } from 'react'; - -import FormField from './FormField'; import { TextArea } from '@iota/apps-ui-kit'; type TextAreaFieldProps = { @@ -13,9 +11,5 @@ type TextAreaFieldProps = { } & ComponentProps; export const TextAreaField = forwardRef( - ({ label, ...props }, forwardedRef) => ( - -