From 49ffd0f4e1e4a31511bf5b22534c74b55bd7a1b7 Mon Sep 17 00:00:00 2001 From: AlexisG Date: Tue, 9 Jan 2024 18:28:59 +0100 Subject: [PATCH 1/2] refactor: Remove useless useSessionStorage hook --- .../components/Hooks/useSessionstorage.jsx | 33 ----------- .../Hooks/useSessionstorage.spec.jsx | 58 ------------------- 2 files changed, 91 deletions(-) delete mode 100644 packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.jsx delete mode 100644 packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.spec.jsx diff --git a/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.jsx b/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.jsx deleted file mode 100644 index acc3abf92f..0000000000 --- a/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.jsx +++ /dev/null @@ -1,33 +0,0 @@ -// TODO Move to cozy-client -import { useState, useCallback } from 'react' - -import minilog from 'cozy-minilog' - -const log = minilog('useSessionstorage') - -export const useSessionstorage = (key, initialValue) => { - const [sessionValue, setSessionValueState] = useState(() => { - try { - const item = window.sessionStorage.getItem(key) - return item ? JSON.parse(item) : initialValue - } catch (error) { - log.error('Get item in sessionStorage failed', error) - return initialValue - } - }) - - const setSessionValue = useCallback( - value => { - try { - const valueToStore = - value instanceof Function ? value(sessionValue) : value - setSessionValueState(valueToStore) - window.sessionStorage.setItem(key, JSON.stringify(valueToStore)) - } catch (error) { - log.error('Set item in sessionStorage failed', error) - } - }, - [key, sessionValue] - ) - return [sessionValue, setSessionValue] -} diff --git a/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.spec.jsx b/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.spec.jsx deleted file mode 100644 index 3d701852f3..0000000000 --- a/packages/cozy-mespapiers-lib/src/components/Hooks/useSessionstorage.spec.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { - render, - cleanup, - getByTestId, - fireEvent, - act -} from '@testing-library/react' -import React from 'react' - -import { useSessionstorage } from './useSessionstorage' - -describe('useSessionstorage defined', () => { - it('should be defined', () => { - expect(useSessionstorage).toBeDefined() - }) -}) - -describe('useSessionstorage basic', () => { - let App - beforeEach(() => { - // eslint-disable-next-line react/display-name - App = function () { - const [value, set] = useSessionstorage('test-key', 'test value') - - return ( -
-

{value}

- -
- ) - } - }) - - afterEach(cleanup) - - it('initializes correctly', () => { - const { container } = render() - const valueElement = getByTestId(container, 'value') - - expect(valueElement.innerHTML).toBe('test value') - }) - - it('setting the new value', () => { - const { container } = render() - const setToNewValueButton = getByTestId(container, 'new-value') - act(() => fireEvent.click(setToNewValueButton)) - const valueElement = getByTestId(container, 'value') - - expect(valueElement.innerHTML).toBe('new test value') - }) -}) From e866b6cd4a49761fe08164c33cb98a72370bc970 Mon Sep 17 00:00:00 2001 From: AlexisG Date: Tue, 9 Jan 2024 19:16:49 +0100 Subject: [PATCH 2/2] 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 +++-- .../ModelSteps/ContactDialog.spec.jsx | 1 + .../src/components/ModelSteps/ContactList.jsx | 91 +++++++++++++------ 3 files changed, 76 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/ContactDialog.spec.jsx b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.spec.jsx index e784aa4838..12e82413f7 100644 --- a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.spec.jsx +++ b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactDialog.spec.jsx @@ -29,6 +29,7 @@ jest.mock('./widgets/ConfirmReplaceFile', () => () => ( jest.mock('./widgets/SubmitButton', () => () => (
)) +jest.mock('./ContactList', () => () =>
) /* eslint-enable react/display-name */ const setup = ({ diff --git a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx index 625929a483..6d8a034257 100644 --- a/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx +++ b/packages/cozy-mespapiers-lib/src/components/ModelSteps/ContactList.jsx @@ -1,6 +1,7 @@ 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 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 +10,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 { 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 +35,40 @@ const ContactList = ({ onSelection }) => { const { t } = useI18n() + const client = useClient() - const [contactsLocalSession, setContactLocalSession] = useSessionstorage( - 'contactList', - [] + const { data: settingsData, ...settingsQuery } = useQuery( + getAppSettings.definition, + getAppSettings.options ) - const [contactsList, setContactsList] = useState([ - currentUser, - ...contactsLocalSession - ]) + const isLoadingSettings = isQueryLoading(settingsQuery) + + const suggestedContactIds = settingsData[0]?.suggestedContactIds || [] + const contactsQueryByIds = buildContactsQueryByIds( + suggestedContactIds, + !isLoadingSettings + ) + const { data: contacts, ...contactQueryResult } = useQueryAll( + contactsQueryByIds.definition, + contactsQueryByIds.options + ) + const isLoadingContacts = + isQueryLoading(contactQueryResult) || contactQueryResult.hasMore + + 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 +85,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 +153,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,