Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/components/Actions/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const edit = () => {
cozyUrl: client.getStackClient().uri,
subDomainType: client.getInstanceOptions().subdomain,
pathname: '/',
hash: `/${contactId}/edit`
hash: `/${contactId}/edit?backToRoot=true`
})

window.open(webLink, '_self')
Expand Down
7 changes: 4 additions & 3 deletions src/components/AppRouter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import App from './App'
import AppLayout from './AppLayout'
import ContactImportationModal from './ContactImportationModal'
import ConfirmDeleteModal from './Modals/ConfirmDeleteModal'
import ContactFormModal from './Modals/ContactFormModal'
import CreateModal from './Modals/ContactFormModal/CreateModal'
import EditModal from './Modals/ContactFormModal/EditModal'
import ContactInfoModal from './Modals/ContactInfoModal'
import GroupDeleteConfirmationModal from './Modals/GroupDeleteConfirmationModal'

Expand All @@ -25,9 +26,9 @@ const AppRouter = ({ withTopBar }) => {
<Route element={<AppLayout withTopBar={withTopBar} />}>
<Route path="/" element={<OutletWrapper Component={App} />}>
<Route path="import" element={<ContactImportationModal />} />
<Route path="new" element={<ContactFormModal />} />
<Route path="new" element={<CreateModal />} />
<Route path=":contactId" element={<ContactInfoModal />} />
<Route path=":contactId/edit" element={<ContactFormModal />} />
<Route path=":contactId/edit" element={<EditModal />} />
<Route path=":contactId/delete" element={<ConfirmDeleteModal />} />
<Route
path="group/:groupId/delete/:groupName"
Expand Down
36 changes: 36 additions & 0 deletions src/components/Modals/ContactFormModal/CreateModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import { useNavigate } from 'react-router-dom'

import { useClient, useQueryAll } from 'cozy-client'
import AddModal from 'cozy-ui/transpiled/react/Contacts/AddModal'
import { useSelectedGroup } from 'cozy-ui/transpiled/react/Contacts/GroupsSelect/GroupsSelectProvider'

import { createOrUpdateContact } from '@/connections/allContacts'
import { buildContactsQueryByFamilyNameGivenNameEmailCozyUrl } from '@/queries/queries'

const CreateModal = () => {
const navigate = useNavigate()
const client = useClient()
const { selectedGroup } = useSelectedGroup()

const contactsQueryByFamilyNameGivenNameEmailCozyUrl =
buildContactsQueryByFamilyNameGivenNameEmailCozyUrl()

const contacts = useQueryAll(
contactsQueryByFamilyNameGivenNameEmailCozyUrl.definition,
contactsQueryByFamilyNameGivenNameEmailCozyUrl.options
)

const onSubmit = async formData =>
await createOrUpdateContact({
client,
formData,
selectedGroup
})

const onClose = () => navigate('/')

return <AddModal contacts={contacts} onSubmit={onSubmit} onClose={onClose} />
}

export default CreateModal
113 changes: 113 additions & 0 deletions src/components/Modals/ContactFormModal/CreateModal.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { render, screen, fireEvent, act } from '@testing-library/react'
import React from 'react'
import { useParams } from 'react-router-dom'

import { useQueryAll, useQuery } from 'cozy-client'

import CreateModal from './CreateModal'

import { createOrUpdateContact } from '@/connections/allContacts'
import AppLike from '@/tests/Applike'

jest.mock('@/connections/allContacts', () => ({
createOrUpdateContact: jest.fn()
}))
jest.mock('cozy-client/dist/hooks', () => ({
...jest.requireActual('cozy-client/dist/hooks'),
useQueryAll: jest.fn(),
useQuery: jest.fn()
}))
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn()
}))

describe('CreateModal component', () => {
it('should not call the create function if any of the required fields are missing', async () => {
const formData = {
company: 'Cozy Cloud'
}
useQuery.mockReturnValue({
data: undefined
})
useQueryAll.mockReturnValue({
data: []
})
useParams.mockReturnValue({
contactId: 'ID'
})

render(
<AppLike>
<CreateModal />
</AppLike>
)

act(() => {
fireEvent.change(screen.getByLabelText('Company'), {
target: { value: formData.company }
})
})
expect(screen.getByLabelText('Company').value).toBe('Cozy Cloud')

act(() => {
fireEvent.click(screen.getByText('Save'))
})

expect(createOrUpdateContact).not.toBeCalled()
})

it('should pass a new contact to the creation function', async () => {
const formData = {
firstname: 'bob'
}
useQuery.mockReturnValue({
data: undefined
})
useQueryAll.mockReturnValue({
data: []
})
useParams.mockReturnValue({
contactId: 'ID'
})

const expected = {
address: [],
birthday: '',
birthplace: '',
gender: '',
company: '',
cozy: [],
displayName: 'bob',
email: [],
impp: [],
fullname: 'bob',
indexes: { byFamilyNameGivenNameEmailCozyUrl: 'bob' },
jobTitle: '',
metadata: { cozy: true, version: 1 },
name: { familyName: '', givenName: 'bob' },
note: '',
phone: [],
relationships: { groups: { data: [] }, related: { data: [] } }
}

render(
<AppLike>
<CreateModal />
</AppLike>
)

fireEvent.change(screen.getByLabelText('Firstname'), {
target: { value: formData.firstname }
})

fireEvent.click(screen.getByText('Save'))

expect(createOrUpdateContact).toBeCalledWith({
client: expect.anything(),
oldContact: undefined,
formData: expected,
selectedGroup: expect.anything()
})
})
})
70 changes: 70 additions & 0 deletions src/components/Modals/ContactFormModal/EditModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'

import { useClient, useQuery, useQueryAll } from 'cozy-client'
import AddModal from 'cozy-ui/transpiled/react/Contacts/AddModal'
import { useSelectedGroup } from 'cozy-ui/transpiled/react/Contacts/GroupsSelect/GroupsSelectProvider'

import { createOrUpdateContact } from '@/connections/allContacts'
import { makeContactWithIdentitiesAddresses } from '@/helpers/contacts'
import {
buildContactsQueryByFamilyNameGivenNameEmailCozyUrl,
buildIdentitiesQueryByContact
} from '@/queries/queries'

const EditModal = () => {
const navigate = useNavigate()
const { contactId } = useParams()
const [searchParams] = useSearchParams()
const client = useClient()
const { selectedGroup } = useSelectedGroup()

const backToRoot = searchParams.get('backToRoot')

const contactsQueryByFamilyNameGivenNameEmailCozyUrl =
buildContactsQueryByFamilyNameGivenNameEmailCozyUrl()

const contacts = useQueryAll(
contactsQueryByFamilyNameGivenNameEmailCozyUrl.definition,
contactsQueryByFamilyNameGivenNameEmailCozyUrl.options
)

const contact = contacts?.data?.find(contact => contact._id === contactId)

const isContactsQueryEnabled =
contact && contact.me && contact.address?.length === 0

const indentitiesContactsQueryById = buildIdentitiesQueryByContact(
isContactsQueryEnabled
)
const { data: identities } = useQuery(
indentitiesContactsQueryById.definition,
indentitiesContactsQueryById.options
)

const contactWithIdentitiesAddresses = makeContactWithIdentitiesAddresses(
contact,
identities
)

const onSubmit = async formData =>
await createOrUpdateContact({
client,
oldContact: contact,
formData,
selectedGroup
})

const onClose = () => (backToRoot ? navigate('/') : navigate(`/${contactId}`))

return (
<AddModal
contacts={contacts}
contact={contactWithIdentitiesAddresses}
onSubmit={onSubmit}
onClose={onClose}
/>
)
}

export default EditModal
Loading