Skip to content

Commit

Permalink
style(suite): style add contact modal
Browse files Browse the repository at this point in the history
  • Loading branch information
jvaclavik committed Dec 11, 2024
1 parent bfa15cf commit 74ee006
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 108 deletions.
74 changes: 74 additions & 0 deletions packages/suite/src/views/contacts/AddNewContactModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useState } from 'react';

import { Column, Input, NewModal, Textarea } from '@trezor/components';
import { selectDevice } from '@suite-common/wallet-core';
import { spacings } from '@trezor/theme';

import { useSelector } from '../../hooks/suite';
import { getDeviceState } from '../../reducers/suite/contactsReducer';
import { useAddContact } from './useAddContact';

type AddNewContactModalProps = {
onClose: () => void;
};

export const AddNewContactModal = ({ onClose }: AddNewContactModalProps) => {
const device = useSelector(selectDevice);
const deviceState = device && getDeviceState(device);

const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [label, setLabel] = useState('');
const [address, setAddress] = useState('');

const addContact = useAddContact(onClose, label, address);
const onAddContact = async () => {
const { error } = await addContact();
setErrorMessage(error);
};

if (!deviceState || errorMessage)
return (
<NewModal
onCancel={onClose}
iconName="warningFilled"
variant="warning"
size="small"
bottomContent={
<NewModal.Button variant="tertiary" onClick={onClose}>
Close
</NewModal.Button>
}
>
No device selected or device unacquired
</NewModal>
);

return (
<NewModal
heading="Add new contact"
onCancel={onClose}
size="medium"
bottomContent={
<>
<NewModal.Button onClick={onAddContact}>Save</NewModal.Button>
<NewModal.Button variant="tertiary" onClick={onClose}>
Cancel
</NewModal.Button>
</>
}
>
<Column gap={spacings.sm}>
<Input
value={label}
label="Label for this recipient"
onChange={event => setLabel(event.target.value)}
/>
<Textarea
value={address}
label="Recipient's address or public key"
onChange={event => setAddress(event.target.value)}
/>
</Column>
</NewModal>
);
};
87 changes: 87 additions & 0 deletions packages/suite/src/views/contacts/ContactList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Button, Card, Dropdown, Table, Text } from '@trezor/components';
import { spacings } from '@trezor/theme';

import { Contact } from '../../types/suite';

const ContactItem = ({
contact: { address, label, signature },
remove,
}: {
contact: Contact;
remove: () => void;
}) => {
return (
<Table.Row>
<Table.Cell>
<Text typographyStyle="highlight">{label}</Text>
</Table.Cell>
<Table.Cell>
<Text variant="tertiary" typographyStyle="hint" overflowWrap="anywhere">
{address}
</Text>
</Table.Cell>
<Table.Cell>
<Text variant="tertiary" typographyStyle="hint" overflowWrap="anywhere">
{signature}
</Text>
</Table.Cell>
<Table.Cell align="right">
<Dropdown
alignMenu="bottom-right"
items={[
{
key: '1',
label: 'Contact',
options: [
{
label: 'Delete',
icon: 'userMinusFilled',
onClick: remove,
},
],
},
]}
/>
</Table.Cell>
</Table.Row>
);
};

export const ContactList = ({
contacts,
remove,
onAdd,
}: {
contacts: Contact[];
remove: (contact: Contact) => void;
onAdd: () => void;
}) => {
return (
<Card paddingType="none" overflow="hidden">
<Table isRowHighlightedOnHover margin={{ top: spacings.xs }}>
<Table.Header>
<Table.Row>
<Table.Cell>Label</Table.Cell>
<Table.Cell>Address</Table.Cell>
<Table.Cell>Signature</Table.Cell>
<Table.Cell />
</Table.Row>
</Table.Header>
<Table.Body>
{contacts.map((contact, i) => (
<ContactItem key={i} contact={contact} remove={() => remove(contact)} />
))}
</Table.Body>
<Table.Footer>
<Table.Row hasBorderTop={true} isHighlightedOnHover={false}>
<Table.Cell colSpan={4}>
<Button onClick={onAdd} size="small" icon="plus">
Add new contact
</Button>
</Table.Cell>
</Table.Row>
</Table.Footer>
</Table>
</Card>
);
};
111 changes: 18 additions & 93 deletions packages/suite/src/views/contacts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useState } from 'react';

import { verify } from 'bitcoinjs-message';

import TrezorConnect from '@trezor/connect';
import { Banner, Button, Card, Dropdown, Row, Table, Text } from '@trezor/components';
import { Banner, Button, Row } from '@trezor/components';
import { selectDevice } from '@suite-common/wallet-core';
import { TrezorDevice } from '@suite-common/suite-types';
import { spacings } from '@trezor/theme';
Expand All @@ -12,90 +14,8 @@ import * as contactsActions from 'src/actions/suite/contactsActions';
import { Contact } from 'src/types/suite';

import { SettingsLayout } from '../../components/settings';
import { useAddContactButton } from './useAddContactButton';

const ContactItem = ({
contact: { address, label, signature },
remove,
}: {
contact: Contact;
remove: () => void;
}) => {
return (
<Table.Row>
<Table.Cell>
<Text typographyStyle="highlight">{label}</Text>
</Table.Cell>
<Table.Cell>
<Text variant="tertiary" typographyStyle="hint" overflowWrap="anywhere">
{address}
</Text>
</Table.Cell>
<Table.Cell>
<Text variant="tertiary" typographyStyle="hint" overflowWrap="anywhere">
{signature}
</Text>
</Table.Cell>
<Table.Cell align="right">
<Dropdown
alignMenu="bottom-right"
items={[
{
key: '1',
label: 'Contact',
options: [
{
label: 'Delete',
icon: 'userMinusFilled',
onClick: remove,
},
],
},
]}
/>
</Table.Cell>
</Table.Row>
);
};

const ContactList = ({
contacts,
remove,
}: {
contacts: Contact[];
remove: (contact: Contact) => void;
}) => {
const onAdd = useAddContactButton();

return (
<Card paddingType="none" overflow="hidden">
<Table isRowHighlightedOnHover margin={{ top: spacings.xs }}>
<Table.Header>
<Table.Row>
<Table.Cell>Label</Table.Cell>
<Table.Cell>Address</Table.Cell>
<Table.Cell>Signature</Table.Cell>
<Table.Cell />
</Table.Row>
</Table.Header>
<Table.Body>
{contacts.map((contact, i) => (
<ContactItem key={i} contact={contact} remove={() => remove(contact)} />
))}
</Table.Body>
<Table.Footer>
<Table.Row hasBorderTop={true} isHighlightedOnHover={false}>
<Table.Cell colSpan={4}>
<Button onClick={onAdd} size="small" icon="plus">
Add new contact
</Button>
</Table.Cell>
</Table.Row>
</Table.Footer>
</Table>
</Card>
);
};
import { AddNewContactModal } from './AddNewContactModal';
import { ContactList } from './ContactList';

const FindContactButton = ({ contacts }: { contacts: Contact[] }) => {
const findContact = () => {
Expand Down Expand Up @@ -157,7 +77,11 @@ const GetMyPubkeyButton = () => {
const Contacts = ({ device }: { device: TrezorDevice }) => {
const contacts = useSelector(selectContactsForDevice(device));
const dispatch = useDispatch();
const onAdd = useAddContactButton();
const [isAddNewContactModalVisible, setAddNewContactModalVisible] = useState(false);

const onAdd = () => {
setAddNewContactModalVisible(true);
};

const removeContact = (contact: Contact) => {
const confirmed = confirm('Do you want to remove this contact?');
Expand All @@ -169,7 +93,7 @@ const Contacts = ({ device }: { device: TrezorDevice }) => {
return (
<>
{contacts.length ? (
<ContactList contacts={contacts} remove={removeContact} />
<ContactList contacts={contacts} remove={removeContact} onAdd={onAdd} />
) : (
<Banner
variant="info"
Expand All @@ -183,12 +107,13 @@ const Contacts = ({ device }: { device: TrezorDevice }) => {
You have no contacts yet
</Banner>
)}
<div>
<Row gap={spacings.sm}>
<GetMyPubkeyButton />
<FindContactButton contacts={contacts} />
</Row>
</div>
<Row gap={spacings.sm}>
<GetMyPubkeyButton />
<FindContactButton contacts={contacts} />
</Row>
{isAddNewContactModalVisible && (
<AddNewContactModal onClose={() => setAddNewContactModalVisible(false)} />
)}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,16 @@ import { useDispatch, useSelector } from '../../hooks/suite';
import { getDeviceState } from '../../reducers/suite/contactsReducer';
import * as contactsActions from '../../actions/suite/contactsActions';

export const useAddContactButton = () => {
export const useAddContact = (onCloseModal: () => void, label: string, address: string) => {
const dispatch = useDispatch();
const device = useSelector(selectDevice);

return async () => {
const deviceState = device && getDeviceState(device);
if (!deviceState) {
alert('No device selected or device unacquired');

return;
}

const address = prompt("Recipient's address or public key");
const label = prompt('Label for this recipient');
if (!deviceState) return { error: 'No device' };

if (!address || !label) {
alert('Missing data');

return;
return { error: 'Missing data' };
}

const message = `${label}/${address}`;
Expand All @@ -37,14 +28,15 @@ export const useAddContactButton = () => {
});

if (!response.success) {
alert(`Signing failed: ${response.payload.error}`);

return;
return { error: `Signing failed: ${response.payload.error}` };
}

const { signature } = response.payload;

const contact = { address, label, signature, deviceState };
dispatch(contactsActions.addContact(contact));
onCloseModal();

return { error: null };
};
};

0 comments on commit 74ee006

Please sign in to comment.