Skip to content

Commit 0fe8ac3

Browse files
committed
feat(mespapiers): Use queries instead of sessionStorage to manage
...contactList when creating a new paper. In the Contact step, we want to keep the previously selected contact list for longer than the duration of a session.
1 parent 49ffd0f commit 0fe8ac3

File tree

3 files changed

+97
-40
lines changed

3 files changed

+97
-40
lines changed

packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.jsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,17 @@ const ContactDialog = ({ currentStep, onClose, onBack, onSubmit }) => {
6767
iconSize="small"
6868
title={t(text)}
6969
text={
70-
currentUser && (
71-
<Paper elevation={2} className="u-mt-1 u-mh-half">
72-
<ContactList
73-
className="u-pv-0"
74-
multiple={multiple}
75-
selected={contactsSelected}
76-
currentUser={currentUser}
77-
onSelection={handleContactSelection}
78-
contactModalOpened={contactModalOpened}
79-
setContactModalOpened={setContactModalOpened}
80-
/>
81-
</Paper>
82-
)
70+
<Paper elevation={2} className="u-mt-1 u-mh-half">
71+
<ContactList
72+
className="u-pv-0"
73+
multiple={multiple}
74+
selected={contactsSelected}
75+
currentUser={currentUser}
76+
onSelection={handleContactSelection}
77+
contactModalOpened={contactModalOpened}
78+
setContactModalOpened={setContactModalOpened}
79+
/>
80+
</Paper>
8381
}
8482
/>
8583
}

packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.spec.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jest.mock('./widgets/ConfirmReplaceFile', () => () => (
2929
jest.mock('./widgets/SubmitButton', () => () => (
3030
<div data-testid="SubmitButton" />
3131
))
32+
jest.mock('./ContactList', () => () => <div data-testid="ContactList" />)
3233
/* eslint-enable react/display-name */
3334

3435
const setup = ({

packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import PropTypes from 'prop-types'
2-
import React, { useState, useMemo } from 'react'
2+
import React, { useCallback, useMemo } from 'react'
33

4+
import { isQueryLoading, useClient, useQuery, useQueryAll } from 'cozy-client'
5+
import useRealtime from 'cozy-realtime/dist/useRealtime'
46
import Avatar from 'cozy-ui/transpiled/react/Avatar'
57
import ContactsListModal from 'cozy-ui/transpiled/react/ContactsListModal'
68
import Divider from 'cozy-ui/transpiled/react/Divider'
@@ -9,16 +11,20 @@ import List from 'cozy-ui/transpiled/react/List'
911
import ListItem from 'cozy-ui/transpiled/react/ListItem'
1012
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
1113
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
14+
import ListItemSkeleton from 'cozy-ui/transpiled/react/Skeletons/ListItemSkeleton'
1215
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
1316

1417
import Contact from './Contact'
15-
import { useSessionstorage } from '../Hooks/useSessionstorage'
18+
import { CONTACTS_DOCTYPE, SETTINGS_DOCTYPE } from '../../doctypes'
19+
import { buildContactsQueryByIds, getAppSettings } from '../../helpers/queries'
1620

1721
const styleAvatar = {
1822
color: 'var(--primaryColor)',
1923
backgroundColor: 'var(--primaryColorLightest)'
2024
}
2125

26+
let contactList = []
27+
2228
const ContactList = ({
2329
multiple,
2430
currentUser,
@@ -30,23 +36,60 @@ const ContactList = ({
3036
onSelection
3137
}) => {
3238
const { t } = useI18n()
39+
const client = useClient()
40+
41+
const { data: settingsData, ...settingsQuery } = useQuery(
42+
getAppSettings.definition,
43+
getAppSettings.options
44+
)
45+
const isLoadingSettings = isQueryLoading(settingsQuery)
3346

34-
const [contactsLocalSession, setContactLocalSession] = useSessionstorage(
35-
'contactList',
36-
[]
47+
const suggestedContactIds = settingsData[0]?.suggestedContactIds || []
48+
const contactsQueryByIds = buildContactsQueryByIds(
49+
suggestedContactIds,
50+
!isLoadingSettings
51+
)
52+
const { data: contacts, ...contactQueryResult } = useQueryAll(
53+
contactsQueryByIds.definition,
54+
contactsQueryByIds.options
3755
)
38-
const [contactsList, setContactsList] = useState([
39-
currentUser,
40-
...contactsLocalSession
41-
])
56+
const isLoadingContacts =
57+
isQueryLoading(contactQueryResult) || contactQueryResult.hasMore
58+
59+
const handleDeletedContact = async contact => {
60+
const matchedContact = suggestedContactIds.find(
61+
suggestedContactId => suggestedContactId === contact._id
62+
)
63+
if (!matchedContact) return null
64+
65+
await client.save({
66+
...settingsData[0],
67+
suggestedContactIds: suggestedContactIds.filter(
68+
suggestedContactId => suggestedContactId !== contact._id
69+
),
70+
_type: SETTINGS_DOCTYPE
71+
})
72+
}
73+
useRealtime(client, {
74+
[CONTACTS_DOCTYPE]: {
75+
deleted: handleDeletedContact
76+
}
77+
})
78+
79+
if (!isLoadingSettings && !isLoadingContacts && currentUser) {
80+
contactList = [currentUser, ...contacts]
81+
}
4282

4383
const idsSelected = useMemo(() => selected.map(v => v._id), [selected])
4484

45-
const onClickContactsListModal = contact => {
46-
const contactAlreadyListed = contactsList.some(cl => cl._id === contact._id)
85+
const onClickContactsListModal = async contact => {
86+
const contactAlreadyListed = contactList.some(cl => cl._id === contact._id)
4787
if (!contactAlreadyListed) {
48-
setContactsList(prev => [...prev, contact])
49-
setContactLocalSession(prev => [...prev, contact])
88+
await client.save({
89+
...settingsData[0],
90+
suggestedContactIds: [...suggestedContactIds, contact._id],
91+
_type: SETTINGS_DOCTYPE
92+
})
5093
}
5194
onSelection(multiple ? [...selected, contact] : [contact])
5295
setContactModalOpened(false)
@@ -63,29 +106,44 @@ const ContactList = ({
63106
else newContactIdSelected.push(newValue)
64107

65108
onSelection(
66-
contactsList.filter(contact =>
109+
contactList.filter(contact =>
67110
newContactIdSelected.includes(contact._id)
68111
)
69112
)
70113
} else {
71-
onSelection(contactsList.filter(contact => contact.id === newValue))
114+
onSelection(contactList.filter(contact => contact.id === newValue))
72115
}
73116
}
74117

118+
// Returns a number of Skeletons based on the number of contactIds in the app settings + the current user
119+
const Skeleton = useCallback(
120+
() =>
121+
Array.from(Array(suggestedContactIds.length + 1), (_, idx) => (
122+
<ListItemSkeleton key={idx} />
123+
)),
124+
[suggestedContactIds.length]
125+
)
126+
75127
return (
76128
<>
77129
<List className={className}>
78-
<div className="u-mah-5 u-ov-auto">
79-
{contactsList.map(contact => (
80-
<Contact
81-
key={contact._id}
82-
contact={contact}
83-
multiple={multiple}
84-
selected={idsSelected.includes(contact._id)}
85-
onSelection={onClickContactLine}
86-
/>
87-
))}
88-
</div>
130+
{contactList.length === 0 &&
131+
(isLoadingSettings || isLoadingContacts) ? (
132+
<Skeleton />
133+
) : (
134+
<div className="u-mah-5 u-ov-auto">
135+
{contactList.map(contact => (
136+
<Contact
137+
key={contact._id}
138+
contact={contact}
139+
multiple={multiple}
140+
selected={idsSelected.includes(contact._id)}
141+
onSelection={onClickContactLine}
142+
/>
143+
))}
144+
</div>
145+
)}
146+
89147
{!withoutDivider && <Divider variant="inset" component="li" />}
90148
<ListItem button onClick={() => setContactModalOpened(true)}>
91149
<ListItemIcon>
@@ -116,7 +174,7 @@ ContactList.propTypes = {
116174
/** Determine whether the user can select several contacts */
117175
multiple: PropTypes.bool.isRequired,
118176
/** Contact object representing the current user */
119-
currentUser: PropTypes.object.isRequired,
177+
currentUser: PropTypes.object,
120178
className: PropTypes.string,
121179
contactModalOpened: PropTypes.bool.isRequired,
122180
setContactModalOpened: PropTypes.func.isRequired,

0 commit comments

Comments
 (0)