From eb40e44b00917875945447972f2ea1852ba2deda Mon Sep 17 00:00:00 2001 From: AlexisG Date: Tue, 9 Jan 2024 19:16:49 +0100 Subject: [PATCH] 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. --- .../components/ModelSteps/ContactDialog.jsx | 24 ++-- .../src/components/ModelSteps/ContactList.jsx | 112 +++++++++++++----- 2 files changed, 96 insertions(+), 40 deletions(-) diff --git a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.jsx b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.jsx index d98a9359af..0b06fa77a8 100644 --- a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.jsx +++ b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.jsx @@ -67,19 +67,17 @@ const ContactDialog = ({ currentStep, onClose, onBack, onSubmit }) => { iconSize="small" title={t(text)} text={ - currentUser && ( - - - - ) + + + } /> } diff --git a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx index 625929a483..8c9224e32b 100644 --- a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx +++ b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx @@ -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' @@ -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, @@ -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) @@ -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) => ( + + )), + [suggestedContactIds.length] + ) + return ( <> -
- {contactsList.map(contact => ( - - ))} -
+ {contactList.length === 0 && + (isLoadingSettings || isLoadingContacts) ? ( + + ) : ( +
+ {contactList.map(contact => ( + + ))} +
+ )} + {!withoutDivider && } setContactModalOpened(true)}> @@ -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,