Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/gator-permissions-snap/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@
"existingPermissionsConfirmButton": {
"message": "Continue"
},
"existingPermissionsExistingMessage": {
"message": "You have granted permissions to this site in the past."
},
"existingPermissionsSimilarMessage": {
"message": "You have granted similar permissions to this site in the past."
},
"existingPermissionsLink": {
"message": "Review them"
},
"chainLabel": {
"message": "Network"
},
Expand Down
32 changes: 5 additions & 27 deletions packages/gator-permissions-snap/src/core/confirmation.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { UserInputEventType } from '@metamask/snaps-sdk';
import type { SnapElement } from '@metamask/snaps-sdk/jsx';
import { Button, Container, Footer } from '@metamask/snaps-sdk/jsx';

import type { DialogInterface } from './dialogInterface';
import type { UserEventDispatcher } from '../userEventDispatcher';
import type { Timeout, TimeoutFactory } from './timeoutFactory';
import type { ConfirmationProps } from './types';
import { t } from '../utils/i18n';

/**
* Dialog for handling user confirmation of permission grants.
* Manages the UI state, timeout behavior, and user interactions.
*/
export class ConfirmationDialog {
static readonly #cancelButton = 'cancel-button';
static readonly cancelButton = 'cancel-button';

static readonly #grantButton = 'grant-button';
static readonly grantButton = 'grant-button';

readonly #dialogInterface: DialogInterface;

Expand All @@ -25,8 +23,6 @@ export class ConfirmationDialog {

#ui: SnapElement;

#isGrantDisabled = true;

#timeout: Timeout | undefined;

#hasTimedOut = false;
Expand Down Expand Up @@ -119,7 +115,7 @@ export class ConfirmationDialog {
});

const { unbind: unbindGrantButtonClick } = this.#userEventDispatcher.on({
elementName: ConfirmationDialog.#grantButton,
elementName: ConfirmationDialog.grantButton,
eventType: UserInputEventType.ButtonClickEvent,
interfaceId,
handler: async () => {
Expand All @@ -141,7 +137,7 @@ export class ConfirmationDialog {
});

const { unbind: unbindCancelButtonClick } = this.#userEventDispatcher.on({
elementName: ConfirmationDialog.#cancelButton,
elementName: ConfirmationDialog.cancelButton,
eventType: UserInputEventType.ButtonClickEvent,
interfaceId,
handler: async () => {
Expand Down Expand Up @@ -184,23 +180,7 @@ export class ConfirmationDialog {
}

#buildConfirmation(): JSX.Element {
return (
<Container>
{this.#ui}
<Footer>
<Button name={ConfirmationDialog.#cancelButton} variant="destructive">
{t('cancelButton')}
</Button>
<Button
name={ConfirmationDialog.#grantButton}
variant="primary"
disabled={this.#isGrantDisabled}
>
{t('grantButton')}
</Button>
</Footer>
</Container>
);
return this.#ui;
}

/**
Expand All @@ -211,13 +191,11 @@ export class ConfirmationDialog {
*/
async updateContent({
ui,
isGrantDisabled,
}: {
ui: SnapElement;
isGrantDisabled: boolean;
}): Promise<void> {
this.#ui = ui;
this.#isGrantDisabled = isGrantDisabled;

await this.#dialogInterface.show(this.#buildConfirmation());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import {
Box,
Button,
Container,
Section,
Footer,
Heading,
Text,
Address,
Divider,
Bold,
Skeleton,
Container,
Button,
Footer,
} from '@metamask/snaps-sdk/jsx';
import type { SnapElement } from '@metamask/snaps-sdk/jsx';
import { Hex } from '@metamask/utils';

import { groupPermissionsByFromAddress } from './permissionFormatter';
Expand All @@ -23,65 +19,6 @@ import { t } from '../../utils/i18n';
export const EXISTING_PERMISSIONS_CONFIRM_BUTTON =
'existing-permissions-confirm';

// Maximum number of permissions to display per account
const MAX_PERMISSIONS_PER_ACCOUNT = 3;

/**
* Builds a skeleton loading state for the existing permissions dialog.
* Shows placeholder UI while permissions are being fetched and formatted.
*
* @param config - The configuration for the existing permissions display (used for title/description).
* @returns The skeleton loading UI as a JSX.Element.
*/
export function buildExistingPermissionsSkeletonContent(
config: ExistingPermissionDisplayConfig,
): SnapElement {
const { title, description, buttonLabel } = config;

return (
<Container>
<Box direction="vertical">
<Box center={true}>
<Heading size="lg">{t(title)}</Heading>
<Text>{t(description)}</Text>
</Box>

{/* Show 2 skeleton account groups */}
{[0, 1].map((index) => (
<Section key={`skeleton-account-${index}`}>
<Box direction="vertical">
<Box direction="horizontal" alignment="space-between">
<Text fontWeight="bold">{t('accountLabel')}</Text>
<Skeleton />
</Box>
<Divider />
{/* Show 2 skeleton permission cards */}
{[0, 1].map((permIndex) => (
<Box
key={`skeleton-permission-${permIndex}`}
direction="vertical"
>
{permIndex > 0 && <Divider />}
<Box direction="vertical">
<Skeleton />
<Skeleton />
<Skeleton />
</Box>
</Box>
))}
</Box>
</Section>
))}
</Box>
<Footer>
<Button name={EXISTING_PERMISSIONS_CONFIRM_BUTTON} disabled={true}>
{t(buttonLabel)}
</Button>
</Footer>
</Container>
);
}

/**
* Builds the existing permissions display content.
* Shows a comparison between an existing permission and what the user is about to grant.
Expand All @@ -105,42 +42,20 @@ export function buildExistingPermissionsContent(
</Box>

{Object.entries(grouped).map(([accountAddress, permissions]) => {
const displayedPermissions = permissions.slice(
0,
MAX_PERMISSIONS_PER_ACCOUNT,
);
const hasMorePermissions =
permissions.length > MAX_PERMISSIONS_PER_ACCOUNT;
const moreCount = permissions.length - MAX_PERMISSIONS_PER_ACCOUNT;

return (
<Section key={`account-${accountAddress}`}>
<Box direction="vertical">
<Box direction="horizontal" alignment="space-between">
<Text fontWeight="bold">{t('accountLabel')}</Text>
<Address address={accountAddress as Hex} displayName={true} />
</Box>
<Divider />
{displayedPermissions.map((detail, index) => (
<PermissionCard
key={`permission-${index}`}
detail={detail}
index={index}
/>
))}
{hasMorePermissions && (
<Box direction="vertical">
<Divider />
<Text>
{moreCount === 1
? t('morePermissionsCountSingle')
: t('morePermissionsCountPlural', [String(moreCount)])}
<Bold>{t('dappConnectionsLink')}</Bold>
</Text>
</Box>
)}
</Box>
</Section>
<Box key={`account-${accountAddress}`} direction="vertical">
<Section direction="horizontal" alignment="space-between">
<Text fontWeight="bold">{t('accountLabel')}</Text>
<Address address={accountAddress as Hex} displayName={true} />
</Section>
{permissions.map((detail, index) => (
<PermissionCard
key={`permission-${index}`}
detail={detail}
index={index}
/>
))}
</Box>
);
})}
</Box>
Expand Down
Loading
Loading