diff --git a/apps/photos/public/locales/en/translation.json b/apps/photos/public/locales/en/translation.json index 4f034e120..0a7591eb8 100644 --- a/apps/photos/public/locales/en/translation.json +++ b/apps/photos/public/locales/en/translation.json @@ -357,7 +357,9 @@ "MODIFY_SHARING": "Modify sharing", "ADD_COLLABORATORS": "Add collaborators", "ADD_NEW_EMAIL": "Add a new email", - "SHARE_WITH_PEOPLE":"Share with specific people", + "shared_with_people_zero" :"Share with specific people", + "shared_with_people_one": "Shared with 1 person", + "shared_with_people_other": "Shared with {{count, number}} people", "ADD_VIEWERS":"Add viewers", "PARTICIPANTS": " Participants", "CHANGE_PERMISSIONS_TO_VIEWER": "

{{selectedEmail}} will not be able to add more photos to the album

They will still be able to remove photos added by them

", @@ -373,6 +375,7 @@ "REMOVE_PARTICIPANT_HEAD": "Remove participant", "OWNER": "Owner", "COLLABORATORS": "Collaborators", + "ADD_MORE": "Add more", "VIEWERS": "Viewers", "OR_ADD_EXISTING": "or an add existing one", "REMOVE_PARTICIPANT_MESSAGE": "

{{selectedEmail}} will be removed from the album

Any photos added by them will also be removed from the album

", diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/AddPartipantForm.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/AddPartipantForm.tsx index 52c630a24..72c63aac1 100644 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/AddPartipantForm.tsx +++ b/apps/photos/src/components/Collections/CollectionShare/EmailShare/AddPartipantForm.tsx @@ -141,56 +141,64 @@ export default function AddParticipantForm(props: AddParticipantFormProps) { autoComplete={props.autoComplete} /> - - - - {updatedOptionsList.map((item, index) => ( - <> - { - if ( + + {updatedOptionsList.length > 0 && ( + + + + {updatedOptionsList.map((item, index) => ( + <> + { + if ( + values.selectedOptions.includes( + item + ) + ) { + setFieldValue( + 'selectedOptions', + values.selectedOptions.filter( + ( + selectedOption + ) => + selectedOption !== + item + ) + ); + } else { + setFieldValue( + 'selectedOptions', + [ + ...values.selectedOptions, + item, + ] + ); + } + }} + label={item} + startIcon={ + + } + endIcon={ values.selectedOptions.includes( item - ) - ) { - setFieldValue( - 'selectedOptions', - values.selectedOptions.filter( - (selectedOption) => - selectedOption !== - item - ) - ); - } else { - setFieldValue( - 'selectedOptions', - [ - ...values.selectedOptions, - item, - ] - ); + ) ? ( + + ) : null } - }} - label={item} - startIcon={} - endIcon={ - values.selectedOptions.includes( - item - ) ? ( - - ) : null - } - /> - {index !== - props.optionsList.length - 1 && ( - - )} - - ))} - - + /> + {index !== + props.optionsList.length - + 1 && } + + ))} + + + )} void; - collectionUnshare: (email: string) => Promise; -} - -export function CollaboratorParticipants({ - collection, - onRootClose, - collectionUnshare, -}: Iprops) { - if (!collection.sharees?.length) { - return <>; - } - - const [collaborators, setCollaborators] = useState([]); - const [participantRoleView, setParticipantRoleView] = useState(false); - const [selectedEmail, setSelectedEmail] = useState(''); - - const openParticipantRoleView = (email) => { - setParticipantRoleView(true); - setSelectedEmail(email); - }; - const closeParticipantRoleView = () => { - setParticipantRoleView(false); - }; - - useEffect(() => { - const collaboratorEmails = - collection.sharees - ?.filter((sharee) => sharee.role === 'COLLABORATOR') - .map((sharee) => sharee.email) || []; - setCollaborators(collaboratorEmails); - }, [collection.sharees]); - - return ( - - - - {t('Collaborators')} - - - - {collaborators.map((item, index) => ( - <> - openParticipantRoleView(item)} - label={item} - startIcon={} - endIcon={} - /> - {index !== collaborators.length - 1 && ( - - )} - - ))} - {}} - collection={collection} - onRootClose={onRootClose} - /> - - - - ); -} diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipants.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipants.tsx index 41cab84ea..5b8d30964 100644 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipants.tsx +++ b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipants.tsx @@ -1,100 +1,222 @@ -import { Stack, Typography, styled } from '@mui/material'; +import { Stack } from '@mui/material'; +import { COLLECTION_ROLE, Collection } from 'types/collection'; +import { EnteDrawer } from 'components/EnteDrawer'; +import { t } from 'i18next'; +import { DialogProps } from '@mui/material'; +import Titlebar from 'components/Titlebar'; +import { useContext, useState } from 'react'; +import { AppContext } from 'pages/_app'; +import { GalleryContext } from 'pages/gallery'; +import { unshareCollection } from 'services/collectionService'; import { EnteMenuItem } from 'components/Menu/EnteMenuItem'; import { MenuItemGroup } from 'components/Menu/MenuItemGroup'; -import { Collection } from 'types/collection'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import { useState } from 'react'; -import { t } from 'i18next'; import Avatar from 'components/pages/gallery/Avatar'; +import MenuSectionTitle from 'components/Menu/MenuSectionTitle'; +import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; +import ModeEditIcon from '@mui/icons-material/ModeEdit'; import MenuItemDivider from 'components/Menu/MenuItemDivider'; -import NumberAvatar from '@mui/material/Avatar'; -import ManageParticipantsOptions from './ManageParticipantsOptions'; -import Workspaces from '@mui/icons-material/Workspaces'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import ModifyParticipant from './ModifyParticipant'; +import AddParticipant from './AddParticipant'; +import { useRef } from 'react'; +import Add from '@mui/icons-material/Add'; interface Iprops { collection: Collection; + open: boolean; + onClose: () => void; onRootClose: () => void; + peopleCount: number; } -const AvatarContainer = styled('div')({ - position: 'relative', - display: 'flex', - alignItems: 'center', - marginLeft: -5, -}); - -const AvatarContainerOuter = styled('div')({ - position: 'relative', - display: 'flex', - alignItems: 'center', - marginLeft: 8, -}); -const AvatarCounter = styled(NumberAvatar)({ - height: 20, - width: 20, - fontSize: 10, - color: '#fff', -}); - export default function ManageParticipants({ + open, collection, + onClose, onRootClose, + peopleCount, }: Iprops) { - const [manageAddViewer, setManageAddViewer] = useState(false); - const closeManageAddViewer = () => setManageAddViewer(false); - const openManageAddViewer = () => setManageAddViewer(true); - const peopleCount = collection.sharees.length; + const appContext = useContext(AppContext); + const galleryContext = useContext(GalleryContext); + + const [addParticipantView, setAddParticipantView] = useState(false); + const [participantRoleView, setParticipantRoleView] = useState(false); + const [selectedEmail, setSelectedEmail] = useState(''); + + const closeAddParticipant = () => setAddParticipantView(false); + const openAddParticipant = () => setAddParticipantView(true); + + const participantType = useRef< + COLLECTION_ROLE.COLLABORATOR | COLLECTION_ROLE.VIEWER + >(); + + const openAddCollab = () => { + participantType.current = COLLECTION_ROLE.COLLABORATOR; + openAddParticipant(); + }; + + const openAddViewer = () => { + participantType.current = COLLECTION_ROLE.VIEWER; + openAddParticipant(); + }; + + const handleRootClose = () => { + onClose(); + onRootClose(); + }; + const handleDrawerClose: DialogProps['onClose'] = (_, reason) => { + if (reason === 'backdropClick') { + handleRootClose(); + } else { + onClose(); + } + }; + + const collectionUnshare = async (email: string) => { + try { + appContext.startLoading(); + await unshareCollection(collection, email); + await galleryContext.syncWithRemote(false, true); + } finally { + appContext.finishLoading(); + } + }; + + const ownerEmail = + galleryContext.user.id === collection.owner?.id + ? galleryContext.user.email + : collection.owner?.email; + + const isOwner = galleryContext.user.id === collection.owner?.id; + + const collaborators = collection.sharees + ?.filter((sharee) => sharee.role === COLLECTION_ROLE.COLLABORATOR) + .map((sharee) => sharee.email); + + const viewers = + collection.sharees + ?.filter((sharee) => sharee.role === COLLECTION_ROLE.VIEWER) + .map((sharee) => sharee.email) || []; + + const openParticipantRoleView = (email) => { + setParticipantRoleView(true); + setSelectedEmail(email); + }; + const closeParticipantRoleView = () => { + setParticipantRoleView(false); + }; - const shareeCount = collection.sharees?.length || 0; - const extraShareeCount = Math.max(0, shareeCount - 6); return ( <> - - - - {t(`Shared with ${peopleCount} people`)} - - - - {collection.sharees - ?.slice(0, 6) - .map((sharee) => ( - - - - ))} - {extraShareeCount > 0 && ( - - - +{extraShareeCount} - - - )} - - } - onClick={openManageAddViewer} - label={ - collection.sharees.length === 1 - ? t(collection.sharees[0]?.email) - : null - } - endIcon={} + + + - - - + + + } + /> + + {}} + label={isOwner ? t('YOU') : ownerEmail} + startIcon={} + /> + + + + } + /> + + {collaborators.map((item, index) => ( + <> + + openParticipantRoleView(item) + } + label={item} + startIcon={} + endIcon={} + /> + {index !== collaborators.length - 1 && ( + + )} + + ))} - } + fontWeight={'bold'} + onClick={openAddCollab} + label={ + collaborators?.length + ? t('ADD_MORE') + : t('ADD_COLLABORATORS') + } + /> + + + + } + /> + + {viewers.map((item, index) => ( + <> + + openParticipantRoleView(item) + } + label={item} + startIcon={} + endIcon={} + /> + {index !== collaborators.length - 1 && ( + + )} + + ))} + } + fontWeight={'bold'} + onClick={openAddViewer} + label={ + viewers?.length + ? t('ADD_MORE') + : t('ADD_VIEWERS') + } + /> + + + + + + + ); diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsList.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsList.tsx deleted file mode 100644 index 2e700afe9..000000000 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Box } from '@mui/material'; -import React, { useContext } from 'react'; -import { Collection } from 'types/collection'; -import { OwnerParticipant } from './OwnerParticipant'; -import { ViewerParticipants } from './ViewerParticipants'; -import { CollaboratorParticipants } from './CollaboratorParticipants'; -import { unshareCollection } from 'services/collectionService'; -import { AppContext } from 'pages/_app'; -import { GalleryContext } from 'pages/gallery'; - -interface Iprops { - collection: Collection; - onRootClose: () => void; -} - -export function ManageParticipantsList({ collection, onRootClose }: Iprops) { - if (!collection.sharees?.length) { - return <>; - } - const appContext = useContext(AppContext); - const galleryContext = useContext(GalleryContext); - - const collectionUnshare = async (email: string) => { - try { - appContext.startLoading(); - await unshareCollection(collection, email); - await galleryContext.syncWithRemote(false, true); - } finally { - appContext.finishLoading(); - } - }; - - return ( - - - - - - ); -} diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsOptions.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsOptions.tsx deleted file mode 100644 index a640229ca..000000000 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsOptions.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Stack } from '@mui/material'; -import { Collection } from 'types/collection'; -import { EnteDrawer } from 'components/EnteDrawer'; -import { t } from 'i18next'; -import { DialogProps } from '@mui/material'; -import Titlebar from 'components/Titlebar'; -import { ManageParticipantsList } from './ManageParticipantsList'; - -interface Iprops { - collection: Collection; - - open: boolean; - onClose: () => void; - onRootClose: () => void; - - peopleCount: number; -} - -export default function ManageParticipantsOptions({ - open, - collection, - onClose, - onRootClose, - peopleCount, -}: Iprops) { - const handleDrawerClose: DialogProps['onClose'] = (_, reason) => { - if (reason === 'backdropClick') { - onRootClose(); - } else { - onClose(); - } - }; - - return ( - <> - - - - - - - - - - ); -} diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsRole.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ModifyParticipant.tsx similarity index 99% rename from apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsRole.tsx rename to apps/photos/src/components/Collections/CollectionShare/EmailShare/ModifyParticipant.tsx index 5625f0a45..20ec8c009 100644 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ManageParticipantsRole.tsx +++ b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ModifyParticipant.tsx @@ -28,7 +28,7 @@ interface Iprops { collectionUnshare: (email: string) => Promise; } -export default function ManageParticipantsRole({ +export default function ModifyParticipant({ collection, open, onClose, diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/OwnerParticipant.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/OwnerParticipant.tsx deleted file mode 100644 index 2c9bfb295..000000000 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/OwnerParticipant.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Box, Typography } from '@mui/material'; -import React from 'react'; -import { t } from 'i18next'; -import { Collection } from 'types/collection'; -import { MenuItemGroup } from 'components/Menu/MenuItemGroup'; -import { EnteMenuItem } from 'components/Menu/EnteMenuItem'; -import Avatar from 'components/pages/gallery/Avatar'; -import { User } from 'types/user'; -import { LS_KEYS, getData } from 'utils/storage/localStorage'; - -import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; -interface Iprops { - collection: Collection; -} - -export function OwnerParticipant({ collection }: Iprops) { - if (!collection.sharees?.length) { - return <>; - } - const user: User = getData(LS_KEYS.USER); - - const ownerEmail = - user.id === collection.owner?.id ? t('YOU') : collection.owner?.email; - - return ( - - - - {t('OWNER')} - - - - <> - console.log('clicked', ownerEmail)} - label={ownerEmail} - startIcon={ - - } - /> - - - - ); -} diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ViewerParticipants.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/ViewerParticipants.tsx deleted file mode 100644 index 7abb91e30..000000000 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/ViewerParticipants.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { Box, Stack, Typography } from '@mui/material'; -import React, { useEffect, useState } from 'react'; -import { t } from 'i18next'; -import { Collection } from 'types/collection'; -import { MenuItemGroup } from 'components/Menu/MenuItemGroup'; -import { EnteMenuItem } from 'components/Menu/EnteMenuItem'; -import MenuItemDivider from 'components/Menu/MenuItemDivider'; -import Avatar from 'components/pages/gallery/Avatar'; -import AddViewer from './AddViewer'; -import PhotoIcon from '@mui/icons-material/Photo'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import ManageParticipantsRole from './ManageParticipantsRole'; - -interface Iprops { - collection: Collection; - onRootClose: () => void; - collectionUnshare: (email: string) => Promise; -} - -export function ViewerParticipants({ - collection, - onRootClose, - collectionUnshare, -}: Iprops) { - if (!collection.sharees?.length) { - return <>; - } - - const [Viewers, setViewers] = useState([]); - const [participantRoleView, setParticipantRoleView] = useState(false); - const [selectedEmail, setSelectedEmail] = useState(''); - - const openParticipantRoleView = (email) => { - setParticipantRoleView(true); - setSelectedEmail(email); - }; - const closeParticipantRoleView = () => { - setParticipantRoleView(false); - }; - - useEffect(() => { - const viewersEmails = - collection.sharees - ?.filter((sharee) => sharee.role === 'VIEWER') - .map((sharee) => sharee.email) || []; - setViewers(viewersEmails); - }, [collection.sharees]); - - return ( - <> - - - - - {t('VIEWERS')} - - - <> - {Viewers.map((item, index) => ( - <> - - openParticipantRoleView(item) - } - label={item} - startIcon={} - endIcon={} - /> - {index !== Viewers.length - 1 && ( - - )} - - ))} - {}} - collection={collection} - onRootClose={onRootClose} - /> - - - - - - - ); -} diff --git a/apps/photos/src/components/Collections/CollectionShare/EmailShare/index.tsx b/apps/photos/src/components/Collections/CollectionShare/EmailShare/index.tsx index 05ea4d69d..3a6159ae5 100644 --- a/apps/photos/src/components/Collections/CollectionShare/EmailShare/index.tsx +++ b/apps/photos/src/components/Collections/CollectionShare/EmailShare/index.tsx @@ -1,7 +1,6 @@ -import React, { useState } from 'react'; -import { Collection } from 'types/collection'; +import React, { useRef, useState } from 'react'; +import { COLLECTION_ROLE, Collection } from 'types/collection'; -import ManageParticipants from './ManageParticipants'; import { Stack } from '@mui/material'; import MenuSectionTitle from 'components/Menu/MenuSectionTitle'; import { t } from 'i18next'; @@ -10,8 +9,10 @@ import { MenuItemGroup } from 'components/Menu/MenuItemGroup'; import { EnteMenuItem } from 'components/Menu/EnteMenuItem'; import MenuItemDivider from 'components/Menu/MenuItemDivider'; import AddIcon from '@mui/icons-material/Add'; -import AddViewer from './AddViewer'; -import AddCollab from './AddCollab'; +import AddParticipant from './AddParticipant'; +import ManageParticipants from './ManageParticipants'; +import AvatarGroup from 'components/pages/gallery/AvatarGroup'; +import ChevronRight from '@mui/icons-material/ChevronRight'; export default function EmailShare({ collection, @@ -20,28 +21,55 @@ export default function EmailShare({ collection: Collection; onRootClose: () => void; }) { - const [addViewerView, setAddViewerView] = useState(false); - const [addCollabView, setAddCollabView] = useState(false); + const [addParticipantView, setAddParticipantView] = useState(false); + const [manageParticipantView, setManageParticipantView] = useState(false); - const closeAddViewer = () => setAddViewerView(false); - const openAddViewer = () => setAddViewerView(true); + const closeAddParticipant = () => setAddParticipantView(false); + const openAddParticipant = () => setAddParticipantView(true); - const closeAddCollab = () => setAddCollabView(false); - const openAddCollab = () => setAddCollabView(true); + const closeManageParticipant = () => setManageParticipantView(false); + const openManageParticipant = () => setManageParticipantView(true); + + const participantType = useRef< + COLLECTION_ROLE.COLLABORATOR | COLLECTION_ROLE.VIEWER + >(); + + const openAddCollab = () => { + participantType.current = COLLECTION_ROLE.COLLABORATOR; + openAddParticipant(); + }; + + const openAddViewer = () => { + participantType.current = COLLECTION_ROLE.VIEWER; + openAddParticipant(); + }; return ( <> } /> {collection.sharees.length > 0 ? ( - + <> + + } + onClick={openManageParticipant} + label={ + collection.sharees.length === 1 + ? t(collection.sharees[0]?.email) + : null + } + endIcon={} + /> + + ) : null} } @@ -56,15 +84,17 @@ export default function EmailShare({ /> - - diff --git a/apps/photos/src/components/Collections/CollectionShare/index.tsx b/apps/photos/src/components/Collections/CollectionShare/index.tsx index 8909e9843..8d7bb1c6b 100644 --- a/apps/photos/src/components/Collections/CollectionShare/index.tsx +++ b/apps/photos/src/components/Collections/CollectionShare/index.tsx @@ -44,7 +44,13 @@ function CollectionShare({ collectionSummary, ...props }: Props) { diff --git a/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx b/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx index f95ea34b9..5014c721a 100644 --- a/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx +++ b/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx @@ -58,7 +58,6 @@ const MapBox: React.FC = ({ } else { if (mapContainer && mapContainer.hasChildNodes()) { if (mapContainer.firstChild) { - console.log('removing child'); mapContainer.removeChild(mapContainer.firstChild); } } diff --git a/apps/photos/src/components/pages/gallery/Avatar.tsx b/apps/photos/src/components/pages/gallery/Avatar.tsx index 79c217d6e..2872a7676 100644 --- a/apps/photos/src/components/pages/gallery/Avatar.tsx +++ b/apps/photos/src/components/pages/gallery/Avatar.tsx @@ -34,6 +34,9 @@ const Avatar: React.FC = ({ file, email }) => { useLayoutEffect(() => { try { + if (!file) { + return; + } if (file.ownerID !== user.id) { // getting email from in-memory id-email map const email = userIDToEmailMap.get(file.ownerID); @@ -66,21 +69,21 @@ const Avatar: React.FC = ({ file, email }) => { useLayoutEffect(() => { try { if (!email) { - logError(Error(), 'email not found in userIDToEmailMap'); return; } - const id = Array.from(userIDToEmailMap.keys()).find( - (key) => userIDToEmailMap.get(key) === email - ); - if (!id && user.email !== email) { - logError(Error(), `ID not found for email: ${email}`); - return; - } else if (!id && user.email === email) { + if (user.email === email) { setUserLetter(email[0].toUpperCase()); setColorCode(PUBLIC_COLLECTED_FILES_AVATAR_COLOR_CODE); return; } + const id = Array.from(userIDToEmailMap.keys()).find( + (key) => userIDToEmailMap.get(key) === email + ); + if (!id) { + logError(Error(), `ID not found for email: ${email}`); + return; + } const colorIndex = id % theme.colors.avatarColors.length; const colorCode = theme.colors.avatarColors[colorIndex]; setUserLetter(email[0].toUpperCase()); diff --git a/apps/photos/src/components/pages/gallery/AvatarGroup.tsx b/apps/photos/src/components/pages/gallery/AvatarGroup.tsx new file mode 100644 index 000000000..3eab966a8 --- /dev/null +++ b/apps/photos/src/components/pages/gallery/AvatarGroup.tsx @@ -0,0 +1,48 @@ +import { styled } from '@mui/material'; +import NumberAvatar from '@mui/material/Avatar'; +import Avatar from './Avatar'; +import { Collection } from 'types/collection'; + +const AvatarContainer = styled('div')({ + position: 'relative', + display: 'flex', + alignItems: 'center', + marginLeft: -5, +}); + +const AvatarContainerOuter = styled('div')({ + position: 'relative', + display: 'flex', + alignItems: 'center', + marginLeft: 8, +}); +const AvatarCounter = styled(NumberAvatar)({ + height: 20, + width: 20, + fontSize: 10, + color: '#fff', +}); + +const SHAREE_AVATAR_LIMIT = 6; + +const AvatarGroup = ({ sharees }: { sharees: Collection['sharees'] }) => { + const hasShareesOverLimit = sharees?.length > SHAREE_AVATAR_LIMIT; + const countOfShareesOverLimit = sharees?.length - SHAREE_AVATAR_LIMIT; + + return ( + + {sharees?.slice(0, 6).map((sharee) => ( + + + + ))} + {hasShareesOverLimit && ( + + +{countOfShareesOverLimit} + + )} + + ); +}; + +export default AvatarGroup;