Skip to content

Commit

Permalink
feat(wallet-dashboard): add settings menu and network switcher (#4509)
Browse files Browse the repository at this point in the history
* feat: add settings menu and network switcher

* fix: reset react queries

* fix: change notifications for toast

* fix: view enums and icon ordering in top nav
  • Loading branch information
brancoder authored Dec 18, 2024
1 parent 683e71d commit a0d25ff
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { SettingsDialog, useSettingsDialog } from '@/components';
import { Badge, BadgeType, Button, ButtonType } from '@iota/apps-ui-kit';
import { ConnectButton, useIotaClientContext } from '@iota/dapp-kit';
import { getNetwork, Network } from '@iota/iota-sdk/client';
import { ThemeSwitcher } from '@iota/core';
import { ConnectButton } from '@iota/dapp-kit';
import { Settings } from '@iota/ui-icons';

export function TopNav() {
const { network } = useIotaClientContext();
const { name: networkName } = getNetwork(network);
const {
isSettingsDialogOpen,
settingsDialogView,
setSettingsDialogView,
onCloseSettingsDialogClick,
onOpenSettingsDialogClick,
} = useSettingsDialog();

return (
<div className="flex w-full flex-row items-center justify-end gap-md py-xs--rs">
<Badge label="Mainnet" type={BadgeType.PrimarySoft} />
<Badge
label={networkName}
type={network === Network.Mainnet ? BadgeType.PrimarySoft : BadgeType.Neutral}
/>
<ConnectButton size="md" />
<SettingsDialog
isOpen={isSettingsDialogOpen}
handleClose={onCloseSettingsDialogClick}
view={settingsDialogView}
setView={setSettingsDialogView}
/>
<ThemeSwitcher />
<Button icon={<Settings />} type={ButtonType.Ghost} />
<Button
icon={<Settings />}
type={ButtonType.Ghost}
onClick={onOpenSettingsDialogClick}
/>
</div>
);
}
1 change: 1 addition & 0 deletions apps/wallet-dashboard/components/Dialogs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export * from './ReceiveFundsDialog';
export * from './Staking';
export * from './unstake';
export * from './vesting';
export * from './settings';
export * from './MigrationDialog';
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import { Dialog } from '@iota/apps-ui-kit';
import { SettingsDialogView } from './enums';
import { SettingsListView, NetworkSelectorView } from './views';

interface SettingsDialogProps {
isOpen: boolean;
handleClose: () => void;
view: SettingsDialogView | undefined;
setView: (view: SettingsDialogView) => void;
}

export function SettingsDialog({
isOpen,
handleClose,
view,
setView,
}: SettingsDialogProps): JSX.Element {
function onBack(): void {
setView(SettingsDialogView.SelectSetting);
}

return (
<Dialog open={isOpen} onOpenChange={() => handleClose()}>
<>
{view === SettingsDialogView.SelectSetting && (
<SettingsListView handleClose={handleClose} setView={setView} />
)}
{view === SettingsDialogView.NetworkSettings && (
<NetworkSelectorView handleClose={handleClose} onBack={onBack} />
)}
</>
</Dialog>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './view.enums';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export enum SettingsDialogView {
SelectSetting = 'SelectSetting',
NetworkSettings = 'NetworkSettings',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './useSettingsDialog';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { useState } from 'react';
import { SettingsDialogView } from '../enums';

export function useSettingsDialog() {
const [settingsDialogView, setSettingsDialogView] = useState<SettingsDialogView | undefined>();

const isSettingsDialogOpen = settingsDialogView !== undefined;

function onCloseSettingsDialogClick() {
setSettingsDialogView(undefined);
}

function onOpenSettingsDialogClick() {
setSettingsDialogView(SettingsDialogView.SelectSetting);
}

return {
isSettingsDialogOpen,
settingsDialogView,
setSettingsDialogView,
onCloseSettingsDialogClick,
onOpenSettingsDialogClick,
};
}
7 changes: 7 additions & 0 deletions apps/wallet-dashboard/components/Dialogs/settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './enums';
export * from './SettingsDialog';
export * from './hooks';
export * from './views';
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import { Header, RadioButton } from '@iota/apps-ui-kit';
import { DialogLayout, DialogLayoutBody } from '../../layout';
import { NetworkConfiguration } from '@iota/iota-sdk/client';
import { useIotaClientContext } from '@iota/dapp-kit';
import toast from 'react-hot-toast';

interface NetworkSelectorViewProps {
handleClose: () => void;
onBack: () => void;
}

export function NetworkSelectorView({
handleClose,
onBack,
}: NetworkSelectorViewProps): JSX.Element {
const clientContext = useIotaClientContext();
const activeNetwork = clientContext.network;

async function handleNetworkChange(network: NetworkConfiguration) {
if (activeNetwork === network.id) {
return;
}
clientContext.selectNetwork(network.id);
toast.success(`Switched to ${network.name}`);
}
return (
<DialogLayout>
<Header title="Network" onClose={handleClose} onBack={onBack} titleCentered />
<DialogLayoutBody>
<div className="flex w-full flex-col gap-md">
{Object.keys(clientContext.networks).map((network) => {
const networkConfig = clientContext.networks[
network
] as NetworkConfiguration;
return (
<div className="px-md" key={networkConfig.id}>
<RadioButton
label={networkConfig.name}
isChecked={activeNetwork === networkConfig.id}
onChange={() => handleNetworkChange(networkConfig)}
/>
</div>
);
})}
</div>
</DialogLayoutBody>
</DialogLayout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import {
Card,
CardAction,
CardActionType,
CardBody,
CardImage,
CardType,
Header,
ImageType,
} from '@iota/apps-ui-kit';
import { DialogLayout, DialogLayoutBody } from '../../layout';
import { SettingsDialogView } from '../enums';
import { getNetwork } from '@iota/iota-sdk/client';
import { useIotaClientContext } from '@iota/dapp-kit';
import { Globe } from '@iota/ui-icons';

interface SettingsListViewProps {
handleClose: () => void;
setView: (view: SettingsDialogView) => void;
}

export function SettingsListView({ handleClose, setView }: SettingsListViewProps): JSX.Element {
const { network } = useIotaClientContext();
const { name: networkName } = getNetwork(network);
function onSelectSettingClick(view: SettingsDialogView): void {
setView(view);
}
const MENU_ITEMS = [
{
title: 'Network',
subtitle: networkName,
icon: <Globe />,
onClick: () => onSelectSettingClick(SettingsDialogView.NetworkSettings),
},
];
return (
<DialogLayout>
<Header title="Settings" onClose={handleClose} onBack={handleClose} titleCentered />
<DialogLayoutBody>
<div className="flex w-full flex-col gap-md">
{MENU_ITEMS.map((item, index) => (
<Card key={index} type={CardType.Default} onClick={item.onClick}>
<CardImage type={ImageType.BgSolid}>
<div className="flex h-10 w-10 items-center justify-center rounded-full text-neutral-10 dark:text-neutral-92 [&_svg]:h-5 [&_svg]:w-5">
<span className="text-2xl">{item.icon}</span>
</div>
</CardImage>
<CardBody title={item.title} subtitle={item.subtitle} />
<CardAction type={CardActionType.Link} />
</Card>
))}
</div>
</DialogLayoutBody>
</DialogLayout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './SettingsListView';
export * from './NetworkSelectorView';
10 changes: 8 additions & 2 deletions apps/wallet-dashboard/providers/AppProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ export function AppProviders({ children }: React.PropsWithChildren) {
const [queryClient] = useState(() => new QueryClient());
const allNetworks = getAllNetworks();
const defaultNetwork = getDefaultNetwork();

function handleNetworkChange() {
queryClient.resetQueries();
}
return (
<GrowthBookProvider growthbook={growthbook}>
<QueryClientProvider client={queryClient}>
<IotaClientProvider networks={allNetworks} defaultNetwork={defaultNetwork}>
<IotaClientProvider
networks={allNetworks}
defaultNetwork={defaultNetwork}
onNetworkChange={handleNetworkChange}
>
<KioskClientProvider>
<WalletProvider
autoConnect={true}
Expand Down

0 comments on commit a0d25ff

Please sign in to comment.