Skip to content

Commit

Permalink
feat(mespapiers): Use queries instead of sessionStorage to manage
Browse files Browse the repository at this point in the history
...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.
  • Loading branch information
Merkur39 committed Jan 10, 2024
1 parent 49ffd0f commit eb40e44
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,17 @@ const ContactDialog = ({ currentStep, onClose, onBack, onSubmit }) => {
iconSize="small"
title={t(text)}
text={
currentUser && (
<Paper elevation={2} className="u-mt-1 u-mh-half">
<ContactList
className="u-pv-0"
multiple={multiple}
selected={contactsSelected}
currentUser={currentUser}
onSelection={handleContactSelection}
contactModalOpened={contactModalOpened}
setContactModalOpened={setContactModalOpened}
/>
</Paper>
)
<Paper elevation={2} className="u-mt-1 u-mh-half">
<ContactList
className="u-pv-0"
multiple={multiple}
selected={contactsSelected}
currentUser={currentUser}
onSelection={handleContactSelection}
contactModalOpened={contactModalOpened}
setContactModalOpened={setContactModalOpened}
/>
</Paper>
}
/>
}
Expand Down
112 changes: 85 additions & 27 deletions packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import PropTypes from 'prop-types'
import React, { useState, useMemo } from 'react'
import React, { useCallback, useMemo } from 'react'

import { isQueryLoading, useClient, useQuery, useQueryAll } from 'cozy-client'
import useRealtime from 'cozy-realtime/dist/useRealtime'
import Avatar from 'cozy-ui/transpiled/react/Avatar'
import ContactsListModal from 'cozy-ui/transpiled/react/ContactsListModal'
import Divider from 'cozy-ui/transpiled/react/Divider'
Expand All @@ -9,16 +11,20 @@ import List from 'cozy-ui/transpiled/react/List'
import ListItem from 'cozy-ui/transpiled/react/ListItem'
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
import ListItemSkeleton from 'cozy-ui/transpiled/react/Skeletons/ListItemSkeleton'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'

import Contact from './Contact'
import { useSessionstorage } from '../Hooks/useSessionstorage'
import { CONTACTS_DOCTYPE, SETTINGS_DOCTYPE } from '../../doctypes'
import { buildContactsQueryByIds, getAppSettings } from '../../helpers/queries'

const styleAvatar = {
color: 'var(--primaryColor)',
backgroundColor: 'var(--primaryColorLightest)'
}

let contactList = []

const ContactList = ({
multiple,
currentUser,
Expand All @@ -30,23 +36,60 @@ const ContactList = ({
onSelection
}) => {
const { t } = useI18n()
const client = useClient()

const { data: settingsData, ...settingsQuery } = useQuery(
getAppSettings.definition,
getAppSettings.options
)
const isLoadingSettings = isQueryLoading(settingsQuery)

const [contactsLocalSession, setContactLocalSession] = useSessionstorage(
'contactList',
[]
const suggestedContactIds = settingsData[0]?.suggestedContactIds || []
const contactsQueryByIds = buildContactsQueryByIds(
suggestedContactIds,
!isLoadingSettings
)
const { data: contacts, ...contactQueryResult } = useQueryAll(
contactsQueryByIds.definition,
contactsQueryByIds.options
)
const [contactsList, setContactsList] = useState([
currentUser,
...contactsLocalSession
])
const isLoadingContacts =
isQueryLoading(contactQueryResult) || contactQueryResult.hasMore

const handleDeletedContact = async contact => {
const matchedContact = suggestedContactIds.find(
suggestedContactId => suggestedContactId === contact._id
)
if (!matchedContact) return null

await client.save({
...settingsData[0],
suggestedContactIds: suggestedContactIds.filter(
suggestedContactId => suggestedContactId !== contact._id
),
_type: SETTINGS_DOCTYPE
})
}
useRealtime(client, {
[CONTACTS_DOCTYPE]: {
deleted: handleDeletedContact
}
})

if (!isLoadingSettings && !isLoadingContacts && currentUser) {
contactList = [currentUser, ...contacts]
}

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

const onClickContactsListModal = contact => {
const contactAlreadyListed = contactsList.some(cl => cl._id === contact._id)
const onClickContactsListModal = async contact => {
const contactAlreadyListed = contactList.some(cl => cl._id === contact._id)
if (!contactAlreadyListed) {
setContactsList(prev => [...prev, contact])
setContactLocalSession(prev => [...prev, contact])
await client.save({
...settingsData[0],
suggestedContactIds: [...suggestedContactIds, contact._id],
_type: SETTINGS_DOCTYPE
})
}
onSelection(multiple ? [...selected, contact] : [contact])
setContactModalOpened(false)
Expand All @@ -63,29 +106,44 @@ const ContactList = ({
else newContactIdSelected.push(newValue)

onSelection(
contactsList.filter(contact =>
contactList.filter(contact =>
newContactIdSelected.includes(contact._id)
)
)
} else {
onSelection(contactsList.filter(contact => contact.id === newValue))
onSelection(contactList.filter(contact => contact.id === newValue))
}
}

// Returns a number of Skeletons based on the number of contactIds in the app settings + the current user
const Skeleton = useCallback(
() =>
Array.from(Array(suggestedContactIds.length + 1), (_, idx) => (
<ListItemSkeleton key={idx} />
)),
[suggestedContactIds.length]
)

return (
<>
<List className={className}>
<div className="u-mah-5 u-ov-auto">
{contactsList.map(contact => (
<Contact
key={contact._id}
contact={contact}
multiple={multiple}
selected={idsSelected.includes(contact._id)}
onSelection={onClickContactLine}
/>
))}
</div>
{contactList.length === 0 &&
(isLoadingSettings || isLoadingContacts) ? (
<Skeleton />
) : (
<div className="u-mah-5 u-ov-auto">
{contactList.map(contact => (
<Contact
key={contact._id}
contact={contact}
multiple={multiple}
selected={idsSelected.includes(contact._id)}
onSelection={onClickContactLine}
/>
))}
</div>
)}

{!withoutDivider && <Divider variant="inset" component="li" />}
<ListItem button onClick={() => setContactModalOpened(true)}>
<ListItemIcon>
Expand Down Expand Up @@ -116,7 +174,7 @@ ContactList.propTypes = {
/** Determine whether the user can select several contacts */
multiple: PropTypes.bool.isRequired,
/** Contact object representing the current user */
currentUser: PropTypes.object.isRequired,
currentUser: PropTypes.object,
className: PropTypes.string,
contactModalOpened: PropTypes.bool.isRequired,
setContactModalOpened: PropTypes.func.isRequired,
Expand Down

0 comments on commit eb40e44

Please sign in to comment.