Skip to content

Commit

Permalink
feat(RecipientList): Show recipient groups
Browse files Browse the repository at this point in the history
  • Loading branch information
cballevre committed Mar 21, 2024
1 parent 4be590d commit 60d155c
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 0 deletions.
14 changes: 14 additions & 0 deletions packages/cozy-sharing/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,19 @@
"title": "Remove me from sharing",
"desc": "You keep the content but it won't be updated between your Cozy anymore."
}
},
"GroupRecipient": {
"secondary": "%{nbMemberReady}/%{nbMember} members",
"secondary_you": "including you"
},
"RevokeGroupItem": {
"revoke": {
"title": "Remove group from sharing",
"desc": "Group members will keep a copy but the changes won't be synchrnoized anymore."
},
"revokeSelf": {
"title": "Remove me from sharing",
"desc": "You keep the content but it won't be updated between your Cozy anymore."
}
}
}
14 changes: 14 additions & 0 deletions packages/cozy-sharing/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -360,5 +360,19 @@
"title": "Arrêter le partage",
"desc": "Vous conservez le contenu mais il ne sera plus mis à jour entre vos Cozy."
}
},
"GroupRecipient": {
"secondary": "%{nbMemberReady}/%{nbMember} membres",
"secondary_you": "dont vous"
},
"RevokeGroupItem": {
"revoke": {
"title": "Arrêter le partage pour le groupe",
"desc": "Les membres du groupe conserveront une copie mais vos changements ne seront plus synchronisés"
},
"revokeSelf": {
"title": "Quitter le partage",
"desc": "Vous conserverez une copie mais vos changements ne seront plus synchronisés."
}
}
}
10 changes: 10 additions & 0 deletions packages/cozy-sharing/src/components/Avatar/GroupAvatar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'

import Avatar from 'cozy-ui/transpiled/react/Avatar'
import TeamIcon from 'cozy-ui/transpiled/react/Icons/Team'

const GroupAvatar = ({ size }) => {
return <Avatar icon={TeamIcon} size={size} />
}

export { GroupAvatar }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GroupAvatar } from './GroupAvatar'

const meta = {
component: GroupAvatar,
args: {}
}

export default meta

export const Default = {
name: 'Default',
args: {}
}
56 changes: 56 additions & 0 deletions packages/cozy-sharing/src/components/Recipient/GroupRecipient.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react'

import { useClient } from 'cozy-client'
import Fade from 'cozy-ui/transpiled/react/Fade'
import ListItem from 'cozy-ui/transpiled/react/ListItem'
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
import ListItemSecondaryAction from 'cozy-ui/transpiled/react/ListItemSecondaryAction'
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
import Typography from 'cozy-ui/transpiled/react/Typography'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'

import { GroupRecipientPermissions } from './GroupRecipientPermissions'
import { FADE_IN_DURATION } from '../../helpers/recipients'
import { GroupAvatar } from '../Avatar/GroupAvatar'

const GroupRecipient = props => {
const { name, members, fadeIn } = props
const { t } = useI18n()
const client = useClient()

const nbMember = members.length
const nbMemberReady = members.filter(
member => !['revoked', 'mail-not-sent'].includes(member.status)
).length
const isCurrentInstanceInsideMembers = members.some(
member => member.instance === client.options.uri
)

return (
<Fade in timeout={fadeIn ? FADE_IN_DURATION : 0}>
<ListItem disableGutters>
<ListItemIcon>
<GroupAvatar size="small" />
</ListItemIcon>
<ListItemText
primary={
<Typography className="u-ellipsis" variant="body1">
{name}
</Typography>
}
secondary={
t('GroupRecipient.secondary', { nbMember, nbMemberReady }) +
(isCurrentInstanceInsideMembers
? ` (${t('GroupRecipient.secondary_you')})`
: '')
}
/>
<ListItemSecondaryAction>
<GroupRecipientPermissions {...props} />
</ListItemSecondaryAction>
</ListItem>
</Fade>
)
}

export { GroupRecipient }
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { GroupRecipient } from './GroupRecipient'

const meta = {
component: GroupRecipient,
args: {
name: 'Family',
isOwner: true,
read_only: false,
members: [
{ status: 'ready' },
{ status: 'mail-not-sent' },
{ status: 'pending' },
{ status: 'revoked' }
],
groupIndex: 0
}
}

export default meta

export const Default = {
name: 'Default',
args: {}
}

export const InstanceInsideMembers = {
name: 'Instance inside members',
args: {
isOwner: false,
instance: 'http://alice.cozy.localhost:8080',
members: [
{ status: 'ready', instance: 'http://alice.cozy.localhost:8080' },
{ status: 'mail-not-sent' },
{ status: 'pending' },
{ status: 'revoked' }
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState, useRef } from 'react'

import { useClient } from 'cozy-client'
import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
import {
makeActions,
divider
} from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'

import { permission } from './actions/permission'
import { revokeGroup } from './actions/revokeGroup'

const GroupRecipientPermissions = ({
isOwner,
instance,
read_only: isReadOnly = false,
className
}) => {
const { t } = useI18n()
const buttonRef = useRef()
const client = useClient()

const [isMenuDisplayed, setMenuDisplayed] = useState(false)

const instanceMatchesClient =
instance !== undefined && instance === client.options.uri
const shouldShowMenu = (instanceMatchesClient && !isOwner) || isOwner

const toggleMenu = () => setMenuDisplayed(!isMenuDisplayed)
const hideMenu = () => setMenuDisplayed(false)

const handleRevocation = () => {
// TODO : Need to be implemented
}

const type = isReadOnly ? 'one-way' : 'two-way'

const actions = makeActions([permission, divider, revokeGroup], {
t,
type,
isOwner,
handleRevocation
})

return (
<div className={className}>
{shouldShowMenu && (
<>
<DropdownButton
ref={buttonRef}
aria-controls="simple-menu"
aria-haspopup="true"
onClick={toggleMenu}
textVariant="body2"
>
{t(`Share.type.${type}`).toLowerCase()}
</DropdownButton>
<ActionsMenu
ref={buttonRef}
open={isMenuDisplayed}
actions={actions}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
autoClose
onClose={hideMenu}
/>
</>
)}
</div>
)
}

export { GroupRecipientPermissions }
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { GroupRecipientPermissions } from './GroupRecipientPermissions'

const meta = {
component: GroupRecipientPermissions,
args: {
onRevoke: () => {},
onRevokeSelf: () => {},
type: 'two-way',
status: 'ready',
groupIndex: 0
},
argTypes: {
status: {
control: 'select',
options: ['ready', 'mail-not-sent', 'pending', 'seen', 'owner'],
defaultValue: 'ready'
},
type: {
control: 'select',
options: ['one-way', 'two-way'],
defaultValue: 'two-way'
}
}
}

export default meta

export const Owner = {
name: 'Owner',
args: {
isOwner: true
}
}

export const Self = {
name: 'Self',
args: {
isOwner: false,
instance: 'http://alice.cozy.localhost:8080'
}
}
17 changes: 17 additions & 0 deletions packages/cozy-sharing/src/components/Recipient/RecipientList.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'

import { GroupRecipient } from './GroupRecipient'
import MemberRecipient from './MemberRecipient'
import { usePrevious } from '../../helpers/hooks'
import { filterAndReworkRecipients } from '../../helpers/recipients'
Expand All @@ -25,6 +26,22 @@ const RecipientList = ({
user => user.email === recipient.email
)

const isGroupRecipient = recipient.members
if (isGroupRecipient) {
return (
<GroupRecipient
{...recipient}
isOwner={isOwner}
key={recipient.index}
document={document}
documentType={documentType}
onRevoke={onRevoke}
onRevokeSelf={onRevokeSelf}
fadeIn={recipient.hasBeenJustAdded}
/>
)
}

return (
<MemberRecipient
{...recipient}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,37 @@ export const Owner = {
isOwner: true
}
}

export const WithGroup = {
name: 'With group',
args: {
recipients: [
...recipients,
{
id: '2c8d4d5abbec5b4606a1ebe01a021dfd',
name: 'Famille',
addedBy: 0,
read_only: false,
index: 0,
members: [
{
status: 'pending',
email: 'ben@gmail.com',
only_in_groups: true,
groups: [0],
type: 'two-way',
index: 1
},
{
status: 'pending',
email: 'bob@gmail.com',
only_in_groups: true,
groups: [0],
type: 'two-way',
index: 2
}
]
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { forwardRef } from 'react'

import ActionsMenuItem from 'cozy-ui/transpiled/react/ActionsMenu/ActionsMenuItem'
import Icon from 'cozy-ui/transpiled/react/Icon'
import ForbiddenIcon from 'cozy-ui/transpiled/react/Icons/Forbidden'
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
import Typography from 'cozy-ui/transpiled/react/Typography'

const revokeGroup = ({ t, isOwner, handleRevocation }) => {
const revokeType = isOwner ? 'revoke' : 'revokeSelf'
const title = t(`RevokeGroupItem.${revokeType}.title`)
const desc = t(`RevokeGroupItem.${revokeType}.desc`)

const icon = ForbiddenIcon

return {
name: 'revokeMember',
label: title,
icon,
action: () => {
handleRevocation()
},
Component: forwardRef(function RevokeMemberItem(props, ref) {
return (
<ActionsMenuItem {...props} ref={ref}>
<ListItemIcon>
<Icon icon={icon} color="var(--errorColor)" />
</ListItemIcon>
<ListItemText
primary={<Typography color="error">{title}</Typography>}
secondary={desc}
/>
</ActionsMenuItem>
)
})
}
}
export { revokeGroup }

0 comments on commit 60d155c

Please sign in to comment.