Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #12 from input-output-hk/etcm-376-address-book-fix…
Browse files Browse the repository at this point in the history
…-delete

[ETCM-376] Address Book - fix delete
  • Loading branch information
qwhex committed Nov 17, 2020
2 parents a2c4ceb + 41c141c commit 074de48
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 30 deletions.
92 changes: 77 additions & 15 deletions src/address-book/AddressBook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import userEvent from '@testing-library/user-event'
import {AddressBook} from './AddressBook'
import {expectNoValidationErrorOnSubmit, createWithProviders} from '../common/test-helpers'

const VALID_ADDRESS = '0xffffffffffffffffffffffffffffffffffffffff'
const VALID_ADDRESS_01 = '0x0000000000000000000000000000000000000000'
const VALID_ADDRESS_02 = '0xffffffffffffffffffffffffffffffffffffffff'

it('can add a new contact', async () => {
const {queryByText, getByLabelText, getByTestId} = render(<AddressBook />, {
wrapper: createWithProviders(),
})

const modalTitle = 'New Contact'

const newContactButton = getByTestId('add-contact-button')
userEvent.click(newContactButton)

// dialog opened
await waitFor(() => expect(queryByText('Edit Contact')).toBeInTheDocument())
// modal opened
await waitFor(() => expect(queryByText(modalTitle)).toBeInTheDocument())

const saveButton = getByTestId('right-button')
expect(saveButton).toBeDisabled()
Expand All @@ -31,7 +34,7 @@ it('can add a new contact', async () => {
fireEvent.change(addressInput, {target: {value: 'not an address'}})
await waitFor(() => expect(queryByText(INVALID_ADDRESS_MSG)).toBeInTheDocument())

fireEvent.change(addressInput, {target: {value: VALID_ADDRESS}})
fireEvent.change(addressInput, {target: {value: VALID_ADDRESS_01}})
await waitFor(() => expect(queryByText(INVALID_ADDRESS_MSG)).not.toBeInTheDocument())

expect(saveButton).toBeDisabled()
Expand All @@ -51,28 +54,30 @@ it('can add a new contact', async () => {
// saving the contact
await expectNoValidationErrorOnSubmit(queryByText, saveButton)

// dialog closed
await waitFor(() => expect(queryByText('Edit Contact')).not.toBeInTheDocument())
// modal closed
await waitFor(() => expect(queryByText(modalTitle)).not.toBeInTheDocument())

// new contact shows up
await waitFor(() => {
expect(queryByText(VALID_ADDRESS)).toBeInTheDocument()
expect(queryByText(VALID_ADDRESS_01)).toBeInTheDocument()
expect(queryByText(FINAL_LABEL)).toBeInTheDocument()
})
})

it('can edit a contact', async () => {
const {queryByText, getByLabelText, getByTestId, getByTitle} = render(<AddressBook />, {
wrapper: createWithProviders({
wallet: {addressBook: {[VALID_ADDRESS]: 'Gandhi'}, accounts: []},
wallet: {addressBook: {[VALID_ADDRESS_01]: 'Gandhi'}, accounts: []},
}),
})

const startEditButton = getByTitle('Edit Contact')
const modalTitle = 'Edit Contact'

const startEditButton = getByTitle(modalTitle)
userEvent.click(startEditButton)

// dialog opened
await waitFor(() => expect(queryByText('Edit Contact')).toBeInTheDocument())
// modal opened
await waitFor(() => expect(queryByText(modalTitle)).toBeInTheDocument())

const saveButton = getByTestId('right-button')
expect(saveButton).toBeEnabled()
Expand All @@ -85,7 +90,7 @@ it('can edit a contact', async () => {
expect(addressInput).toBeDisabled()

// address input shows up with the correct value
expect(addressInput).toHaveValue(VALID_ADDRESS)
expect(addressInput).toHaveValue(VALID_ADDRESS_01)

// label is editable
const labelInput = getByLabelText('Label')
Expand All @@ -100,16 +105,73 @@ it('can edit a contact', async () => {
// saving the contact
await expectNoValidationErrorOnSubmit(queryByText, saveButton)

// dialog closed
await waitFor(() => expect(queryByText('Edit Contact')).not.toBeInTheDocument())
// modal closed
await waitFor(() => expect(queryByText(modalTitle)).not.toBeInTheDocument())

// new contact shows up
await waitFor(() => {
// address is the same
expect(queryByText(VALID_ADDRESS)).toBeInTheDocument()
expect(queryByText(VALID_ADDRESS_01)).toBeInTheDocument()
// previous label doesn't show up
expect(queryByText('Gandhi')).not.toBeInTheDocument()
// new label shows up
expect(queryByText('Ihdnag')).toBeInTheDocument()
})
})

it('can delete a contact', async () => {
const {queryByText, getByTestId, getAllByTitle} = render(<AddressBook />, {
wrapper: createWithProviders({
wallet: {
addressBook: {[VALID_ADDRESS_01]: 'Gandhi', [VALID_ADDRESS_02]: 'Martin'},
accounts: [],
},
}),
})

const modalTitle = 'Delete Contact'

const expectModalOpenedWithCorrectData = (label: string, address: string) => (): void => {
expect(queryByText(modalTitle)).toBeInTheDocument()
expect(queryByText('Are you sure you want to delete this contact?')).toBeInTheDocument()
expect(queryByText(`${label} (${address})`)).toBeInTheDocument()
}

const expectModalClosed = (): void => expect(queryByText(modalTitle)).not.toBeInTheDocument()

const startDeleteButtons = getAllByTitle('Delete Contact')
const startDeleteButtonGandhi = startDeleteButtons[0]
const startDeleteButtonMartin = startDeleteButtons[1]

// ETCM-376: open modal for Gandhi
userEvent.click(startDeleteButtonGandhi)
await waitFor(expectModalOpenedWithCorrectData('Gandhi', VALID_ADDRESS_01))

// cancel deleting Gandhi
const cancelButton = getByTestId('left-button')
expect(cancelButton).toBeEnabled()
userEvent.click(cancelButton)
await waitFor(expectModalClosed)

// check if Martin exists in the address book
expect(queryByText('Martin')).toBeInTheDocument()
expect(queryByText(VALID_ADDRESS_02)).toBeInTheDocument()

// open delete modal for Martin
userEvent.click(startDeleteButtonMartin)
await waitFor(expectModalOpenedWithCorrectData('Martin', VALID_ADDRESS_02))

// delete Martin
const deleteButton = getByTestId('right-button')
expect(deleteButton).toBeEnabled()
userEvent.click(deleteButton)
await waitFor(expectModalClosed)

// data for Martin is deleted, data for Gandhi is still there
await waitFor(() => {
expect(queryByText('Gandhi')).toBeInTheDocument()
expect(queryByText(VALID_ADDRESS_01)).toBeInTheDocument()
expect(queryByText('Martin')).not.toBeInTheDocument()
expect(queryByText(VALID_ADDRESS_02)).not.toBeInTheDocument()
})
})
38 changes: 23 additions & 15 deletions src/address-book/AddressBook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ const ADDRESS_FIELD_NAME = 'contact-address'

type Setter<T> = React.Dispatch<React.SetStateAction<T>>

type ModalId = 'Edit' | 'Delete' | 'none'
type EditMode = 'Add' | 'Edit'

interface EditContactModalProps {
onSave(address: string, label: string): void
onCancel(): void
address: string
label: string
setAddress: Setter<string>
setLabel: Setter<string>
toEdit: boolean
editMode: EditMode
}

const _EditContactModal = ({
Expand All @@ -37,15 +40,19 @@ const _EditContactModal = ({
label,
setAddress,
setLabel,
toEdit,
editMode,
}: EditContactModalProps): JSX.Element => {
const {t} = useTranslation()
const addressValidator = toAntValidator(t, validateAddress)
const modalLocker = ModalLocker.useContainer()

return (
<Dialog
title={t(['addressBook', 'book', 'editContact'])}
title={
editMode === 'Edit'
? t(['addressBook', 'book', 'editContact'])
: t(['addressBook', 'book', 'newContact'])
}
leftButtonProps={{
onClick: onCancel,
disabled: modalLocker.isLocked,
Expand Down Expand Up @@ -74,7 +81,7 @@ const _EditContactModal = ({
addressValidator,
],
}}
disabled={toEdit}
disabled={editMode === 'Edit'}
id={ADDRESS_FIELD_NAME}
/>
<DialogInput
Expand Down Expand Up @@ -137,37 +144,38 @@ const _DeleteContactModal = ({
const DeleteContactModal = wrapWithModal(_DeleteContactModal)
const EditContactModal = wrapWithModal(_EditContactModal)

type ModalId = 'Edit' | 'Delete' | 'none'

const _AddressBook = ({
walletState: {addressBook, editContact, deleteContact},
}: PropsWithWalletState<EmptyProps, LoadedState>): JSX.Element => {
const {t} = useTranslation()
const {copyToClipboard} = useLocalizedUtilities()

const [shownModal, setShownModal] = useState<ModalId>('none')
const [toEdit, setToEdit] = useState(false)
const [editMode, setEditMode] = useState<EditMode>('Edit')
const [selectedAddress, setAddress] = useState('')
const [selectedLabel, setLabel] = useState('')
// eslint-disable-next-line fp/no-mutating-methods
const sortedLabels = [...Object.keys(addressBook)].sort()

const onStartEdit = (address: string, label: string) => () => {
const selectContact = (address: string, label: string): void => {
setAddress(address)
setLabel(label)
}

const onStartEdit = (address: string) => () => {
selectContact(address, addressBook[address])
setEditMode('Edit')
setShownModal('Edit')
setToEdit(true)
}

const onStartAddNew = (): void => {
setAddress('')
setLabel('')
selectContact('', '')
setEditMode('Add')
setShownModal('Edit')
setToEdit(false)
}

const onStartDelete = (address: string) => () => {
setAddress(address)
selectContact(address, addressBook[address])
setShownModal('Delete')
}

Expand Down Expand Up @@ -225,7 +233,7 @@ const _AddressBook = ({
<span
className="edit"
title={t(['addressBook', 'book', 'editContact'])}
{...fillActionHandlers(onStartEdit(address, label))}
{...fillActionHandlers(onStartEdit(address))}
>
<EditOutlined />
</span>
Expand All @@ -244,7 +252,7 @@ const _AddressBook = ({
setLabel={setLabel}
address={selectedAddress}
label={selectedLabel}
toEdit={toEdit}
editMode={editMode}
/>
<DeleteContactModal
visible={shownModal === 'Delete'}
Expand Down
1 change: 1 addition & 0 deletions src/translations/en/renderer.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@
"title": "Address Book",
"addNew": "Add new",
"noData": "No saved contacts",
"newContact": "New Contact",
"editContact": "Edit Contact",
"saveContact": "Save Contact",
"deleteContact": "Delete Contact",
Expand Down

0 comments on commit 074de48

Please sign in to comment.