11import 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'
46import Avatar from 'cozy-ui/transpiled/react/Avatar'
57import ContactsListModal from 'cozy-ui/transpiled/react/ContactsListModal'
68import Divider from 'cozy-ui/transpiled/react/Divider'
@@ -9,16 +11,20 @@ import List from 'cozy-ui/transpiled/react/List'
911import ListItem from 'cozy-ui/transpiled/react/ListItem'
1012import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
1113import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
14+ import ListItemSkeleton from 'cozy-ui/transpiled/react/Skeletons/ListItemSkeleton'
1215import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
1316
1417import 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
1721const styleAvatar = {
1822 color : 'var(--primaryColor)' ,
1923 backgroundColor : 'var(--primaryColorLightest)'
2024}
2125
26+ let contactList = [ ]
27+
2228const 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