Skip to content

Commit

Permalink
Merge pull request #1668 from oasisprotocol/mz/contactsAvailable
Browse files Browse the repository at this point in the history
Make Contacts available only when profile exists
  • Loading branch information
buberdds authored Sep 15, 2023
2 parents 17ae7cb + 58763de commit 045998e
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 47 deletions.
23 changes: 0 additions & 23 deletions playwright/tests/syncTabs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,6 @@ test.describe('syncTabs', () => {
})

test.describe('adding and removing contacts in tabs', () => {
test('unpersisted', async ({ page, context }) => {
await page.goto('/open-wallet/private-key')
await fillPrivateKeyWithoutPassword(page, {
persistenceCheckboxChecked: false,
persistenceCheckboxDisabled: false,
})
const tab2 = await context.newPage()
await testSyncingContacts(page, tab2)
})

test('persisted', async ({ page, context }) => {
await addPersistedStorage(page)
await page.goto('/')
Expand All @@ -162,19 +152,6 @@ test.describe('syncTabs', () => {
await testSyncingContacts(page, tab2)
})

test('incognito', async ({ page, context }) => {
await addPersistedStorage(page)
await page.goto('/')
await page.getByRole('button', { name: 'Continue without the profile' }).click()
const tab2 = await context.newPage()
await tab2.goto('/open-wallet/private-key')
await fillPrivateKeyWithoutPassword(tab2, {
persistenceCheckboxChecked: false,
persistenceCheckboxDisabled: true,
})
await testSyncingContacts(page, tab2)
})

async function testSyncingContacts(page: Page, tab2: Page) {
await page.getByTestId('account-selector').click()
await page.getByTestId('toolbar-contacts-tab').click()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ exports[`<Contacts /> should match snapshot 1`] = `
class="c8"
type="button"
>
toolbar.settings.manageAccount
Manage
</button>
</div>
</div>
Expand All @@ -409,7 +409,7 @@ exports[`<Contacts /> should match snapshot 1`] = `
class="c10"
type="button"
>
toolbar.contacts.add
Add Contact
</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,59 @@
import { render, screen } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import userEvent from '@testing-library/user-event'
import { Provider } from 'react-redux'
import { configureAppStore } from 'store/configureStore'
import { ThemeProvider } from 'styles/theme/ThemeProvider'
import { Wallet } from 'app/state/wallet/types'
import { PersistState } from 'app/state/persist/types'
import { Contacts } from '../'

// needed to test Trans component
jest.unmock('react-i18next')

const renderComponent = (store: any) =>
render(
<Provider store={store}>
<ThemeProvider>
<Contacts />
</ThemeProvider>
<MemoryRouter>
<ThemeProvider>
<Contacts closeHandler={() => {}} />
</ThemeProvider>
</MemoryRouter>
</Provider>,
)

describe('<Contacts />', () => {
let store: ReturnType<typeof configureAppStore>

const unlockedProfile = {
wallet: {
selectedWallet: 'dummy',
wallets: {
dummy: {
address: 'dummy',
} as Wallet,
},
},
persist: {
hasPersistedProfiles: true,
stringifiedEncryptionKey: 'unlockedProfile',
} as PersistState,
}

beforeEach(() => {
store = configureAppStore()
store = configureAppStore(unlockedProfile)
})

it('should render unavailable state', () => {
renderComponent(configureAppStore({}))
expect(screen.getByText(/To start adding contacts create a profile while/)).toBeInTheDocument()
expect(screen.queryByText('Add Contact')).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: 'opening a wallet' })).toBeInTheDocument()
})

it('should match snapshot', () => {
const storeWithContacts = configureAppStore({
...unlockedProfile,
contacts: {
oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4: {
address: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4',
Expand All @@ -36,15 +67,15 @@ describe('<Contacts />', () => {

it('should render empty state', () => {
renderComponent(store)
expect(screen.getByText('toolbar.contacts.emptyList')).toBeInTheDocument()
expect(screen.getByText('toolbar.contacts.add')).toBeInTheDocument()
expect(screen.getByText('You have no contacts yet.')).toBeInTheDocument()
expect(screen.getByText('Add Contact')).toBeInTheDocument()
expect(screen.queryByTestId('account-choice')).not.toBeInTheDocument()
})

it('should show Add Contact form overlay', async () => {
renderComponent(store)
await userEvent.click(screen.getByRole('button', { name: 'toolbar.contacts.add' }))
expect(screen.getByPlaceholderText('toolbar.contacts.name')).toBeInTheDocument()
expect(screen.getByPlaceholderText('toolbar.contacts.address')).toBeInTheDocument()
await userEvent.click(screen.getByRole('button', { name: 'Add Contact' }))
expect(screen.getByPlaceholderText('Name')).toBeInTheDocument()
expect(screen.getByPlaceholderText('Address')).toBeInTheDocument()
})
})
60 changes: 48 additions & 12 deletions src/app/components/Toolbar/Features/Contacts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,73 @@
import { useState, useContext } from 'react'
import { useState, useContext, ReactNode } from 'react'
import { useSelector } from 'react-redux'
import { useTranslation } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { Box } from 'grommet/es6/components/Box'
import { Button } from 'grommet/es6/components/Button'
import { ResponsiveContext } from 'grommet/es6/contexts/ResponsiveContext'
import { Inbox } from 'grommet-icons/es6/icons/Inbox'
import { selectContactsList } from 'app/state/contacts/selectors'
import { selectUnlockedStatus } from 'app/state/selectUnlockedStatus'
import { ContactAccount } from './ContactAccount'
import { AddContact } from './AddContact'
import { layerScrollableAreaHeight } from './layer'

const ContactsListEmptyState = () => {
const { t } = useTranslation()
type ContactsListEmptyStateProps = {
children: ReactNode
}

return (
<Box gap="medium" align="center" pad={{ top: 'large' }}>
<Inbox size="36px" color="currentColor" />
<Box pad="large">{t('toolbar.contacts.emptyList', 'You have no contacts yet.')}</Box>
</Box>
)
const ContactsListEmptyState = ({ children }: ContactsListEmptyStateProps) => (
<Box gap="medium" align="center" pad={{ top: 'large' }}>
<Inbox size="36px" color="currentColor" />
<Box pad="large">{children}</Box>
</Box>
)

interface ContactsProps {
closeHandler: () => any
}

export const Contacts = () => {
export const Contacts = ({ closeHandler }: ContactsProps) => {
const { t } = useTranslation()
const [layerVisibility, setLayerVisibility] = useState(false)
const contacts = useSelector(selectContactsList)
const unlockedStatus = useSelector(selectUnlockedStatus)
const isMobile = useContext(ResponsiveContext) === 'small'
const isAvailable = unlockedStatus === 'unlockedProfile'
const navigate = useNavigate()

if (!isAvailable) {
return (
<ContactsListEmptyState>
<Box style={{ display: 'block' }}>
<Trans
i18nKey="toolbar.contacts.notAvailable"
t={t}
components={{
OpenWalletButton: (
<Button
color="link"
onClick={() => {
closeHandler()
navigate('/open-wallet')
}}
/>
),
}}
defaults="To start adding contacts create a profile while <OpenWalletButton>opening a wallet</OpenWalletButton>."
/>
</Box>
</ContactsListEmptyState>
)
}

return (
<>
{!contacts.length && (
<Box justify="center" flex="grow" height={isMobile ? 'auto' : layerScrollableAreaHeight}>
<ContactsListEmptyState />
<ContactsListEmptyState>
{t('toolbar.contacts.emptyList', 'You have no contacts yet.')}
</ContactsListEmptyState>
</Box>
)}
{!!contacts.length && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const SettingsButton = memo(() => {
<AccountSelector closeHandler={() => setLayerVisibility(false)} />
</Tab>
<Tab data-testid="toolbar-contacts-tab" title={t('toolbar.settings.contacts', 'Contacts')}>
<Contacts />
<Contacts closeHandler={() => setLayerVisibility(false)} />
</Tab>
</Tabs>
</Box>
Expand Down
1 change: 1 addition & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@
"emptyList": "You have no contacts yet.",
"manage": "Manage Contact",
"name": "Name",
"notAvailable": "To start adding contacts create a profile while <OpenWalletButton>opening a wallet</OpenWalletButton>.",
"save": "Save",
"validation": {
"addressError": "Please enter a valid wallet address",
Expand Down
4 changes: 4 additions & 0 deletions src/styles/theme/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ const grommetCustomTheme: ThemeType = {
dark: '#d5d6d7',
light: '#565b61',
},
link: {
dark: '#6FFFB0',
light: '#0092f6',
},
'status-ok': '#2ad5ab',
'status-warning': {
dark: '#f3d45e',
Expand Down

0 comments on commit 045998e

Please sign in to comment.