Merge pull request #32941 from overleaf/ii-share-modal-manage-access
[web] Share modal redesign: invited people screen GitOrigin-RevId: bf7f83dccc245e41eca8087fc27c1b411f025b0d
This commit is contained in:
@@ -965,7 +965,10 @@
|
||||
"invite_more_members": "",
|
||||
"invite_not_accepted": "",
|
||||
"invite_resend_limit_hit": "",
|
||||
"invite_resent": "",
|
||||
"invite_revoked": "",
|
||||
"invite_users": "",
|
||||
"invited_people": "",
|
||||
"invited_to_group": "",
|
||||
"invited_to_group_have_individual_subcription": "",
|
||||
"inviting": "",
|
||||
@@ -1576,6 +1579,7 @@
|
||||
"resend": "",
|
||||
"resend_confirmation_code": "",
|
||||
"resend_group_invite": "",
|
||||
"resend_invite": "",
|
||||
"resend_link_sso": "",
|
||||
"resend_managed_user_invite": "",
|
||||
"resending_confirmation_code": "",
|
||||
|
||||
BIN
Binary file not shown.
@@ -45,6 +45,7 @@ export default /** @type {const} */ ([
|
||||
'lightbulb_2',
|
||||
'lock',
|
||||
'lock_open',
|
||||
'mail',
|
||||
'mode_comment',
|
||||
'more_vert',
|
||||
'neurology',
|
||||
@@ -52,6 +53,8 @@ export default /** @type {const} */ ([
|
||||
'notifications',
|
||||
'open_in_new',
|
||||
'password',
|
||||
'person',
|
||||
'person_edit',
|
||||
'picture_as_pdf',
|
||||
'push_pin',
|
||||
'rate_review',
|
||||
@@ -75,6 +78,7 @@ export default /** @type {const} */ ([
|
||||
'upload',
|
||||
'visibility',
|
||||
'visibility_off',
|
||||
'warning',
|
||||
'web_asset',
|
||||
'whatshot',
|
||||
'wifi_off',
|
||||
|
||||
@@ -15,6 +15,15 @@ import OLCol from '@/shared/components/ol/ol-col'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { useUserContext } from '@/shared/context/user-context'
|
||||
import { upgradePlan } from '@/main/account-upgrade'
|
||||
import ShareProjectModalRow from '@/features/share-project-modal/components/share-project-modal-row'
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from '@/shared/components/dropdown/dropdown-menu'
|
||||
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import classnames from 'classnames'
|
||||
|
||||
type PermissionsOption = PermissionsLevel | 'removeAccess' | 'downgraded'
|
||||
|
||||
@@ -38,6 +47,7 @@ export default function EditMember({
|
||||
canAddCollaborators,
|
||||
isReviewerOnFreeProject,
|
||||
}: EditMemberProps) {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const [privileges, setPrivileges] = useState<PermissionsOption>(
|
||||
member.privileges
|
||||
)
|
||||
@@ -51,8 +61,8 @@ export default function EditMember({
|
||||
setPrivileges(member.privileges)
|
||||
}, [member.privileges])
|
||||
|
||||
const { monitorRequest } = useShareProjectContext()
|
||||
const { projectId, project, updateProject } = useProjectContext()
|
||||
const { monitorRequest, setSuccessActionMessage } = useShareProjectContext()
|
||||
const { projectId, project, updateProject, features } = useProjectContext()
|
||||
const { members, invites } = project || {}
|
||||
const user = useUserContext()
|
||||
|
||||
@@ -113,10 +123,14 @@ export default function EditMember({
|
||||
).then(() => {
|
||||
updateProject({
|
||||
members:
|
||||
members?.map(item =>
|
||||
item._id === member._id ? { ...item, newPrivileges } : item
|
||||
members?.map(
|
||||
(item): ProjectMember =>
|
||||
item._id === member._id
|
||||
? { ...item, privileges: newPrivileges }
|
||||
: item
|
||||
) || [],
|
||||
})
|
||||
setSuccessActionMessage(t('access_updated'))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -136,7 +150,195 @@ export default function EditMember({
|
||||
const confirmRemoval =
|
||||
privileges !== member.privileges && privilegeChangePending
|
||||
|
||||
return (
|
||||
const getDropdownLabel = () => {
|
||||
if (hasBeenDowngraded) {
|
||||
return t('select_access_level')
|
||||
}
|
||||
switch (privileges) {
|
||||
case 'owner':
|
||||
return t('make_owner')
|
||||
case 'readAndWrite':
|
||||
return t('editor')
|
||||
case 'review':
|
||||
return t('reviewer')
|
||||
case 'readOnly':
|
||||
return t('viewer')
|
||||
case 'removeAccess':
|
||||
return t('remove_access')
|
||||
case 'downgraded':
|
||||
return t('select_access_level')
|
||||
default:
|
||||
return t('remove_access')
|
||||
}
|
||||
}
|
||||
|
||||
const getPrivilegeSubtitle = (privilege: PermissionsOption) => {
|
||||
if (!['readAndWrite', 'review'].includes(privilege)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
(hasBeenDowngraded && !confirmRemoval) ||
|
||||
(!canAddCollaborators && !['readAndWrite', 'review'].includes(privileges))
|
||||
) {
|
||||
return t('limited_to_n_collaborators_per_project', {
|
||||
count: features.collaborators,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const isPrivilegeDisabled = (privilege: PermissionsOption) => {
|
||||
return (
|
||||
!canAddCollaborators &&
|
||||
['readAndWrite', 'review'].includes(privilege) &&
|
||||
((hasBeenDowngraded && !confirmRemoval) ||
|
||||
!['readAndWrite', 'review'].includes(privileges))
|
||||
)
|
||||
}
|
||||
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<ShareProjectModalRow>
|
||||
<div className="d-inline-flex align-items-center h5 m-0 gap-2">
|
||||
<MaterialIcon
|
||||
type={
|
||||
shouldWarnMember() || member.pendingEditor || member.pendingReviewer
|
||||
? 'warning'
|
||||
: 'person'
|
||||
}
|
||||
className={
|
||||
shouldWarnMember() || member.pendingEditor || member.pendingReviewer
|
||||
? 'text-warning'
|
||||
: undefined
|
||||
}
|
||||
unfilled
|
||||
/>
|
||||
<div className="px-2">
|
||||
{member.email}
|
||||
{member.pendingEditor && (
|
||||
<div className="small fw-normal">{t('view_only_downgraded')}</div>
|
||||
)}
|
||||
{member.pendingReviewer && (
|
||||
<div className="small fw-normal">
|
||||
{t('view_only_reviewer_downgraded')}
|
||||
</div>
|
||||
)}
|
||||
{shouldWarnMember() && (
|
||||
<div className="small fw-normal">
|
||||
{t('will_lose_edit_access_on_date', {
|
||||
date: linkSharingEnforcementDate,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{isReviewerOnFreeProject && (
|
||||
<div className="small fw-normal">
|
||||
<Trans
|
||||
i18nKey="comment_only_upgrade_to_enable_track_changes"
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<OLButton
|
||||
variant="link"
|
||||
className="btn-inline-link"
|
||||
onClick={() => upgradePlan('track-changes')}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-end">
|
||||
<Dropdown
|
||||
align="end"
|
||||
onSelect={(eventKey: PermissionsOption) => {
|
||||
if (eventKey) {
|
||||
handlePrivilegeChange(eventKey)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
{hasBeenDowngraded && !confirmRemoval && (
|
||||
<MaterialIcon type="warning" unfilled className="text-warning" />
|
||||
)}
|
||||
<DropdownToggle
|
||||
variant="ghost"
|
||||
className="d-flex align-items-center gap-2 no-default-caret"
|
||||
>
|
||||
{getDropdownLabel()}
|
||||
<MaterialIcon type="keyboard_arrow_down" />
|
||||
</DropdownToggle>
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
eventKey="owner"
|
||||
leadingIcon={<MaterialIcon type="person_edit" unfilled />}
|
||||
active={privileges === 'owner'}
|
||||
trailingIcon={privileges === 'owner' ? 'check' : undefined}
|
||||
>
|
||||
{t('make_owner')}
|
||||
</OLDropdownMenuItem>
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
eventKey="readAndWrite"
|
||||
leadingIcon={<MaterialIcon type="edit" unfilled />}
|
||||
active={privileges === 'readAndWrite'}
|
||||
trailingIcon={privileges === 'readAndWrite' ? 'check' : undefined}
|
||||
disabled={isPrivilegeDisabled('readAndWrite')}
|
||||
description={getPrivilegeSubtitle('readAndWrite')}
|
||||
>
|
||||
{t('editor')}
|
||||
</OLDropdownMenuItem>
|
||||
{features.trackChangesVisible && (
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
eventKey="review"
|
||||
leadingIcon={<MaterialIcon type="mode_comment" unfilled />}
|
||||
active={privileges === 'review'}
|
||||
trailingIcon={privileges === 'review' ? 'check' : undefined}
|
||||
disabled={isPrivilegeDisabled('review')}
|
||||
description={getPrivilegeSubtitle('review')}
|
||||
>
|
||||
{t('reviewer')}
|
||||
</OLDropdownMenuItem>
|
||||
)}
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
eventKey="readOnly"
|
||||
leadingIcon={<MaterialIcon type="visibility" unfilled />}
|
||||
active={privileges === 'readOnly'}
|
||||
trailingIcon={privileges === 'readOnly' ? 'check' : undefined}
|
||||
>
|
||||
{t('viewer')}
|
||||
</OLDropdownMenuItem>
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
eventKey="removeAccess"
|
||||
variant="danger"
|
||||
leadingIcon={<MaterialIcon type="block" unfilled />}
|
||||
active={privileges === 'removeAccess'}
|
||||
trailingIcon={privileges === 'removeAccess' ? 'check' : undefined}
|
||||
>
|
||||
{t('remove_access')}
|
||||
</OLDropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
{confirmRemoval && (
|
||||
<form
|
||||
onSubmit={e => {
|
||||
e.preventDefault()
|
||||
if (privilegeChangePending) {
|
||||
commitPrivilegeChange(privileges)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ChangePrivilegesActions
|
||||
handleReset={() => setPrivileges(member.privileges)}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</ShareProjectModalRow>
|
||||
) : (
|
||||
<form
|
||||
id="share-project-form"
|
||||
onSubmit={e => {
|
||||
@@ -322,12 +524,17 @@ type ChangePrivilegesActionsProps = {
|
||||
function ChangePrivilegesActions({
|
||||
handleReset,
|
||||
}: ChangePrivilegesActionsProps) {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className="text-center d-flex gap-1 me-3">
|
||||
<div
|
||||
className={classnames('text-center d-flex gap-1 me-3', {
|
||||
'mt-2 justify-content-end': isSharingUpdatesEnabled,
|
||||
})}
|
||||
>
|
||||
<OLButton
|
||||
type="submit"
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={handleReset}
|
||||
|
||||
@@ -9,8 +9,17 @@ import OLRow from '@/shared/components/ol/ol-row'
|
||||
import OLCol from '@/shared/components/ol/ol-col'
|
||||
import OLTooltip from '@/shared/components/ol/ol-tooltip'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import OLBadge from '@/shared/components/ol/ol-badge'
|
||||
import OLDropdownMenuItem from '@/shared/components/ol/ol-dropdown-menu-item'
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from '@/shared/components/dropdown/dropdown-menu'
|
||||
import ShareProjectModalRow from '@/features/share-project-modal/components/share-project-modal-row'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { ProjectMember } from '@/shared/context/types/project-metadata'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export default function Invite({
|
||||
invite,
|
||||
@@ -19,8 +28,41 @@ export default function Invite({
|
||||
invite: ProjectMember
|
||||
isProjectOwner: boolean
|
||||
}) {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<ShareProjectModalRow>
|
||||
<div className="d-inline-flex align-items-center h5 m-0 gap-2">
|
||||
<MaterialIcon type="person" unfilled />
|
||||
<div className="px-2">{invite.email}</div>
|
||||
<OLBadge bg="light" text="dark">
|
||||
{t('pending_invite')}
|
||||
</OLBadge>
|
||||
</div>
|
||||
{isProjectOwner ? (
|
||||
<Dropdown align="end" onSelect={() => {}}>
|
||||
<DropdownToggle
|
||||
variant="ghost"
|
||||
className="d-flex align-items-center gap-2 no-default-caret"
|
||||
>
|
||||
<MemberPrivileges privileges={invite.privileges} />
|
||||
<MaterialIcon type="keyboard_arrow_down" />
|
||||
</DropdownToggle>
|
||||
<DropdownMenu>
|
||||
<ResendInvite invite={invite} />
|
||||
<RevokeInvite invite={invite} />
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
) : (
|
||||
<div className="h5 m-0 px-4 fw-semibold">
|
||||
<div className="form-control-plaintext border-0">
|
||||
<MemberPrivileges privileges={invite.privileges} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ShareProjectModalRow>
|
||||
) : (
|
||||
<OLRow className="project-invite">
|
||||
<OLCol xs={8}>
|
||||
<div>{invite.email}</div>
|
||||
@@ -45,8 +87,10 @@ export default function Invite({
|
||||
}
|
||||
|
||||
function ResendInvite({ invite }: { invite: ProjectMember }) {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const { t } = useTranslation()
|
||||
const { monitorRequest, setError, inFlight } = useShareProjectContext()
|
||||
const { monitorRequest, setError, inFlight, setSuccessActionMessage } =
|
||||
useShareProjectContext()
|
||||
const { projectId } = useProjectContext()
|
||||
|
||||
// const buttonRef = useRef(null)
|
||||
@@ -54,6 +98,7 @@ function ResendInvite({ invite }: { invite: ProjectMember }) {
|
||||
const handleClick = useCallback(
|
||||
() =>
|
||||
monitorRequest(() => resendInvite(projectId, invite))
|
||||
.then(() => setSuccessActionMessage(t('invite_resent')))
|
||||
.catch(error => {
|
||||
if (error?.response?.status === 404) {
|
||||
setError('invite_expired')
|
||||
@@ -71,10 +116,19 @@ function ResendInvite({ invite }: { invite: ProjectMember }) {
|
||||
;(document.activeElement as HTMLElement).blur()
|
||||
}
|
||||
}),
|
||||
[invite, monitorRequest, projectId, setError]
|
||||
[invite, monitorRequest, projectId, setError, setSuccessActionMessage, t]
|
||||
)
|
||||
|
||||
return (
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
leadingIcon={<MaterialIcon type="mail" unfilled />}
|
||||
onClick={handleClick}
|
||||
disabled={inFlight}
|
||||
>
|
||||
{t('resend_invite')}
|
||||
</OLDropdownMenuItem>
|
||||
) : (
|
||||
<OLButton
|
||||
variant="link"
|
||||
className="btn-inline-link"
|
||||
@@ -88,8 +142,9 @@ function ResendInvite({ invite }: { invite: ProjectMember }) {
|
||||
}
|
||||
|
||||
function RevokeInvite({ invite }: { invite: ProjectMember }) {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const { t } = useTranslation()
|
||||
const { monitorRequest } = useShareProjectContext()
|
||||
const { monitorRequest, setSuccessActionMessage } = useShareProjectContext()
|
||||
const { projectId, project, updateProject } = useProjectContext()
|
||||
const { invites, members } = project || {}
|
||||
|
||||
@@ -107,10 +162,20 @@ function RevokeInvite({ invite }: { invite: ProjectMember }) {
|
||||
current_invites_amount: updatedInvites.length,
|
||||
current_collaborators_amount: members?.length || 0,
|
||||
})
|
||||
setSuccessActionMessage(t('invite_revoked'))
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<OLDropdownMenuItem
|
||||
as="button"
|
||||
leadingIcon={<MaterialIcon type="block" unfilled />}
|
||||
variant="danger"
|
||||
onClick={handleClick}
|
||||
>
|
||||
{t('revoke_invite')}
|
||||
</OLDropdownMenuItem>
|
||||
) : (
|
||||
<OLTooltip
|
||||
id="revoke-invite"
|
||||
description={t('revoke_invite')}
|
||||
|
||||
+57
-3
@@ -1,7 +1,61 @@
|
||||
type InvitedPeopleProps = object
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OwnerInfo from '@/features/share-project-modal/components/owner-info'
|
||||
import EditMember from '@/features/share-project-modal/components/edit-member'
|
||||
import ViewMember from '@/features/share-project-modal/components/view-member'
|
||||
import Invite from '@/features/share-project-modal/components/invite'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import { ProjectMember } from '@/shared/context/types/project-metadata'
|
||||
|
||||
function InvitedPeople(_props: InvitedPeopleProps) {
|
||||
return null
|
||||
type InvitedPeopleProps = {
|
||||
hasExceededCollaboratorLimit: boolean
|
||||
hasTrackChangesFeature: boolean
|
||||
canAddCollaborators: boolean
|
||||
sortedMembers: ProjectMember[]
|
||||
invites?: ProjectMember[]
|
||||
}
|
||||
|
||||
function InvitedPeople({
|
||||
hasExceededCollaboratorLimit,
|
||||
hasTrackChangesFeature,
|
||||
canAddCollaborators,
|
||||
sortedMembers,
|
||||
invites,
|
||||
}: InvitedPeopleProps) {
|
||||
const { t } = useTranslation()
|
||||
const { isProjectOwner } = useEditorContext()
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="h4 fw-normal mt-3 mb-2 pt-1">{t('invited_people')}</h3>
|
||||
<OwnerInfo />
|
||||
{sortedMembers.map(member =>
|
||||
isProjectOwner ? (
|
||||
<EditMember
|
||||
key={member._id}
|
||||
member={member}
|
||||
hasExceededCollaboratorLimit={hasExceededCollaboratorLimit}
|
||||
hasBeenDowngraded={Boolean(
|
||||
member.pendingEditor || member.pendingReviewer
|
||||
)}
|
||||
canAddCollaborators={canAddCollaborators}
|
||||
isReviewerOnFreeProject={
|
||||
member.privileges === 'review' && !hasTrackChangesFeature
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ViewMember key={member._id} member={member} />
|
||||
)
|
||||
)}
|
||||
|
||||
{(invites || []).map(invite => (
|
||||
<Invite
|
||||
key={invite._id}
|
||||
invite={invite}
|
||||
isProjectOwner={isProjectOwner}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default InvitedPeople
|
||||
|
||||
@@ -2,13 +2,26 @@ import { useProjectContext } from '@/shared/context/project-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OLRow from '@/shared/components/ol/ol-row'
|
||||
import OLCol from '@/shared/components/ol/ol-col'
|
||||
import ShareProjectModalRow from '@/features/share-project-modal/components/share-project-modal-row'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export default function OwnerInfo() {
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
const { t } = useTranslation()
|
||||
const { project } = useProjectContext()
|
||||
|
||||
return (
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<ShareProjectModalRow>
|
||||
<div className="d-inline-flex align-items-center h5 m-0 gap-2">
|
||||
<MaterialIcon type="person" unfilled />
|
||||
<div className="px-2">{project?.owner.email}</div>
|
||||
</div>
|
||||
<div className="h5 m-0 px-4 fw-semibold">
|
||||
<div className="form-control-plaintext border-0">{t('owner')}</div>
|
||||
</div>
|
||||
</ShareProjectModalRow>
|
||||
) : (
|
||||
<OLRow className="project-member">
|
||||
<OLCol xs={8}>
|
||||
<div className="project-member-email-icon">
|
||||
|
||||
+7
-1
@@ -134,7 +134,13 @@ export default function ShareModalBody({
|
||||
/>
|
||||
)}
|
||||
{isInvitedPeopleScreen || !isProjectOwner ? (
|
||||
<InvitedPeople />
|
||||
<InvitedPeople
|
||||
sortedMembers={sortedMembers}
|
||||
invites={invites}
|
||||
hasExceededCollaboratorLimit={hasExceededCollaboratorLimit}
|
||||
hasTrackChangesFeature={Boolean(features.trackChanges)}
|
||||
canAddCollaborators={canAddCollaborators}
|
||||
/>
|
||||
) : (
|
||||
<ProjectAccess
|
||||
setIsInvitedPeopleScreen={setIsInvitedPeopleScreen}
|
||||
|
||||
+1
@@ -160,6 +160,7 @@ const ShareProjectModal = React.memo(function ShareProjectModal({
|
||||
// update `error` and `inFlight` while sending a request
|
||||
const monitorRequest = useCallback((request: () => any) => {
|
||||
setError(undefined)
|
||||
setSuccessActionMessage(undefined)
|
||||
setInFlight(true)
|
||||
|
||||
const promise = request()
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
import MemberPrivileges from './member-privileges'
|
||||
import OLRow from '@/shared/components/ol/ol-row'
|
||||
import OLCol from '@/shared/components/ol/ol-col'
|
||||
import ShareProjectModalRow from '@/features/share-project-modal/components/share-project-modal-row'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { ProjectMember } from '@/shared/context/types/project-metadata'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export default function ViewMember({ member }: { member: ProjectMember }) {
|
||||
return (
|
||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||
|
||||
return isSharingUpdatesEnabled ? (
|
||||
<ShareProjectModalRow>
|
||||
<div className="d-inline-flex align-items-center h5 m-0 gap-2">
|
||||
<MaterialIcon type="person" unfilled />
|
||||
<div className="px-2">{member.email}</div>
|
||||
</div>
|
||||
<div className="h5 m-0 px-4 fw-semibold">
|
||||
<div className="form-control-plaintext border-0">
|
||||
<MemberPrivileges privileges={member.privileges} />
|
||||
</div>
|
||||
</div>
|
||||
</ShareProjectModalRow>
|
||||
) : (
|
||||
<OLRow className="project-member">
|
||||
<OLCol xs={8}>
|
||||
<div className="project-member-email-icon">
|
||||
|
||||
@@ -1261,7 +1261,10 @@
|
||||
"invite_not_valid": "This is not a valid project invite",
|
||||
"invite_not_valid_description": "The invite may have expired. Please contact the project owner",
|
||||
"invite_resend_limit_hit": "The invite resend limit hit",
|
||||
"invite_resent": "Invite resent.",
|
||||
"invite_revoked": "Invite revoked.",
|
||||
"invite_users": "Invite users",
|
||||
"invited_people": "Invited people",
|
||||
"invited_to_group": "<0>__inviterName__</0> has invited you to join a group subscription on __appName__",
|
||||
"invited_to_group_have_individual_subcription": "__inviterName__ has invited you to join a group __appName__ subscription. If you join this group, you may not need your individual subscription. Would you like to cancel it?",
|
||||
"invited_to_group_login": "To accept this invitation you need to log in as __emailAddress__.",
|
||||
@@ -2094,6 +2097,7 @@
|
||||
"resend": "Resend",
|
||||
"resend_confirmation_code": "Resend confirmation code",
|
||||
"resend_group_invite": "Resend group invite",
|
||||
"resend_invite": "Resend invite",
|
||||
"resend_link_sso": "Resend SSO invite",
|
||||
"resend_managed_user_invite": "Resend managed user invite",
|
||||
"resending_confirmation_code": "Resending confirmation code",
|
||||
|
||||
Reference in New Issue
Block a user