Skip to content

Commit

Permalink
feat(wallet): rebrand connected dapp details (#2116)
Browse files Browse the repository at this point in the history
* refactor: update styles for the Active Connection page

* fix: rebrand also the list of connected accounts

* fix: update import path

* fix: remove double header

* fix: add fallback for image

Co-authored-by: evavirseda <[email protected]>

* fix: add missing import

---------

Co-authored-by: evavirseda <[email protected]>
Co-authored-by: Begoña Álvarez de la Cruz <[email protected]>
  • Loading branch information
3 people authored Aug 30, 2024
1 parent 9b9c354 commit 3b6e380
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 169 deletions.
4 changes: 3 additions & 1 deletion apps/ui-kit/src/lib/components/molecules/card/CardBody.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ReactNode } from 'react';

export type CardBodyProps = {
title: string;
subtitle?: string;
subtitle?: string | ReactNode;
clickableAction?: React.ReactNode;
};

Expand Down
48 changes: 22 additions & 26 deletions apps/wallet/src/ui/app/components/DAppInfoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import { type PermissionType } from '_src/shared/messaging/messages/payloads/permissions';
import { getValidDAppUrl } from '_src/shared/utils';
import { useAccountByAddress } from '../hooks/useAccountByAddress';
import { Heading } from '../shared/heading';
import { Link } from '../shared/Link';
import { AccountIcon } from './accounts/AccountIcon';
import { AccountItem } from './accounts/AccountItem';
import { useUnlockAccount } from './accounts/UnlockAccountContext';
import { DAppPermissionsList } from './DAppPermissionsList';
import { DAppPermissionList } from './DAppPermissionList';
import { SummaryCard } from './SummaryCard';
import { Link } from 'react-router-dom';
import { Card, CardBody, CardImage, CardType, ImageShape, ImageType } from '@iota/apps-ui-kit';
import { ImageIcon } from '../shared/image-icon';

export interface DAppInfoCardProps {
name: string;
Expand All @@ -29,7 +30,6 @@ export function DAppInfoCard({
permissions,
}: DAppInfoCardProps) {
const validDAppUrl = getValidDAppUrl(url);
const appHostname = validDAppUrl?.hostname ?? url;
const { data: account } = useAccountByAddress(connectedAddress);
const { unlockAccount, lockAccount } = useUnlockAccount();
function handleLockAndUnlockClick() {
Expand All @@ -41,28 +41,24 @@ export function DAppInfoCard({
}
}
return (
<div className="flex flex-col gap-5 bg-white p-6">
<div className="flex flex-row flex-nowrap items-center gap-3.75 py-3">
<div className="bg-steel/20 flex h-15 w-15 shrink-0 grow-0 items-stretch overflow-hidden rounded-2xl">
{iconUrl ? <img className="flex-1" src={iconUrl} alt={name} /> : null}
</div>
<div className="flex flex-col flex-nowrap items-start gap-1 overflow-hidden">
<div className="max-w-full overflow-hidden">
<Heading variant="heading4" weight="semibold" color="gray-100" truncate>
{name}
</Heading>
</div>
<div className="max-w-full overflow-hidden">
<div className="flex flex-col gap-y-md">
<Card type={CardType.Default}>
<CardImage type={ImageType.BgSolid} shape={ImageShape.Rounded}>
<ImageIcon src={iconUrl || null} label={name} fallback={name} />
</CardImage>
<CardBody
title={name}
subtitle={
<Link
href={validDAppUrl?.toString() ?? url}
title={name}
text={appHostname}
color="heroDark"
weight="medium"
/>
</div>
</div>
</div>
to={validDAppUrl?.toString() ?? url}
target="_blank"
rel="noopener noreferrer"
>
{validDAppUrl?.toString() ?? url}
</Link>
}
/>
</Card>
{connectedAddress && account ? (
<AccountItem
icon={<AccountIcon account={account} />}
Expand All @@ -76,7 +72,7 @@ export function DAppInfoCard({
{permissions?.length ? (
<SummaryCard
header="Permissions requested"
body={<DAppPermissionsList permissions={permissions} />}
body={<DAppPermissionList permissions={permissions} />}
boxShadow
/>
) : null}
Expand Down
29 changes: 29 additions & 0 deletions apps/wallet/src/ui/app/components/DAppPermissionList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { type PermissionType } from '_src/shared/messaging/messages/payloads/permissions';
import { SummaryListItem } from './SummaryListItem';
import { Checkmark } from '@iota/ui-icons';

export interface DAppPermissionListProps {
permissions: PermissionType[];
}

const PERMISSION_TYPE_TO_TEXT: Record<PermissionType, string> = {
viewAccount: 'Share wallet address',
suggestTransactions: 'Suggest transactions to approve',
};

export function DAppPermissionList({ permissions }: DAppPermissionListProps) {
return (
<div className="flex flex-col gap-y-xs">
{permissions.map((permissionKey) => (
<SummaryListItem
key={permissionKey}
icon={<Checkmark className="h-5 w-5 text-neutral-10" />}
text={PERMISSION_TYPE_TO_TEXT[permissionKey]}
/>
))}
</div>
);
}
32 changes: 0 additions & 32 deletions apps/wallet/src/ui/app/components/DAppPermissionsList.tsx

This file was deleted.

16 changes: 16 additions & 0 deletions apps/wallet/src/ui/app/components/SummaryListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

interface SummaryListItemProps {
icon: React.ReactNode;
text: string;
}

export function SummaryListItem({ icon, text }: SummaryListItemProps) {
return (
<div className="flex flex-row items-center gap-x-sm">
{icon}
<span className="text-body-md text-neutral-40">{text}</span>
</div>
);
}
23 changes: 23 additions & 0 deletions apps/wallet/src/ui/app/components/SummaryPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Title, TitleSize } from '@iota/apps-ui-kit';
import { type ReactNode } from 'react';

interface SummaryPanelProps {
title: string;
body: ReactNode;
}

export function SummaryPanel({ title, body }: SummaryPanelProps) {
return (
<div className="flex flex-col rounded-xl bg-neutral-96 pb-md">
<div className="flex flex-col gap-y-xs">
<div className="py-2.5">
<Title size={TitleSize.Small} title={title} />
</div>
{body}
</div>
</div>
);
}
123 changes: 51 additions & 72 deletions apps/wallet/src/ui/app/components/WalletListSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,33 @@
// SPDX-License-Identifier: Apache-2.0

import { cx } from 'class-variance-authority';
import { useMemo } from 'react';

import { useAccounts } from '../hooks/useAccounts';
import { Link } from '../shared/Link';
import { SummaryCard } from './SummaryCard';
import { WalletListSelectItem, type WalletListSelectItemProps } from './WalletListSelectItem';
import { useMemo } from 'react';
import { formatAddress } from '@iota/iota-sdk/utils';
import { Checkbox } from '@iota/apps-ui-kit';

export interface WalletListSelectProps {
title: string;
values: string[];
visibleValues?: string[];
mode?: WalletListSelectItemProps['mode'];
mode?: WalletListSelectMode;
disabled?: boolean;
onChange: (values: string[]) => void;
boxShadow?: boolean;
}

enum WalletListSelectMode {
Select = 'select',
Disconnect = 'disconnect',
}

export function WalletListSelect({
title,
values,
visibleValues,
mode = 'select',
disabled = false,
disabled,
onChange,
boxShadow = false,
}: WalletListSelectProps) {
const { data: accounts } = useAccounts();

const filteredAccounts = useMemo(() => {
if (!accounts) {
return [];
Expand All @@ -39,69 +39,48 @@ export function WalletListSelect({
}
return accounts;
}, [accounts, visibleValues]);

function onAccountClick(address: string) {
if (disabled) {
return;
}
const newValues = [];
let found = false;
for (const anAddress of values) {
if (anAddress === address) {
found = true;
continue;
}
newValues.push(anAddress);
}
if (!found) {
newValues.push(address);
}
onChange(newValues);
}

return (
<SummaryCard
header={title}
body={
<ul
className={cx(
'm-0 flex flex-1 list-none flex-col items-stretch self-stretch p-0',
disabled ? 'opacity-70' : '',
)}
>
{filteredAccounts.map(({ address }) => (
<li
key={address}
onClick={() => {
if (disabled) {
return;
}
const newValues = [];
let found = false;
for (const anAddress of values) {
if (anAddress === address) {
found = true;
continue;
}
newValues.push(anAddress);
}
if (!found) {
newValues.push(address);
}
onChange(newValues);
}}
<div className="flex flex-col gap-y-sm">
{filteredAccounts.map(({ address }) => {
const accountAddress = formatAddress(address);
return (
<div
key={address}
className="flex cursor-default flex-row items-center justify-start gap-x-xs py-xxxs"
onClick={() => onAccountClick(address)}
>
<Checkbox name={address} isChecked={values.includes(address)} />
<span
className={cx(
'cursor-default text-body-md text-neutral-40',
disabled && 'text-opacity-40',
)}
>
<WalletListSelectItem
address={address}
selected={values.includes(address)}
mode={mode}
disabled={disabled}
/>
</li>
))}
</ul>
}
footer={
mode === 'select' ? (
<div className="flex flex-row flex-nowrap justify-between self-stretch">
<div>
{filteredAccounts.length > 1 ? (
<Link
color="heroDark"
weight="medium"
text="Select all"
disabled={disabled}
onClick={() =>
onChange(filteredAccounts.map(({ address }) => address))
}
/>
) : null}
</div>
{accountAddress}
</span>
</div>
) : null
}
minimalPadding
boxShadow={boxShadow}
/>
);
})}
</div>
);
}
2 changes: 1 addition & 1 deletion apps/wallet/src/ui/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

export * from './DAppInfoCard';
export * from './DAppPermissionsList';
export * from './DAppPermissionList';
export * from './HideShowDisplayBox';
export * from './IconButton';
export * from './LabelValueItem';
Expand Down
Loading

0 comments on commit 3b6e380

Please sign in to comment.