Merge pull request #33163 from overleaf/ii-share-modal-give-feedback
[web] Share modal give feedback link GitOrigin-RevId: 5e83dec6c6b97c172b7600d8ded285db49178a64
This commit is contained in:
@@ -17,6 +17,7 @@ import { User } from '../../models/User.mjs'
|
|||||||
import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs'
|
import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs'
|
||||||
import SubscriptionHelper from '../Subscription/SubscriptionHelper.mjs'
|
import SubscriptionHelper from '../Subscription/SubscriptionHelper.mjs'
|
||||||
import LimitationsManager from '../Subscription/LimitationsManager.mjs'
|
import LimitationsManager from '../Subscription/LimitationsManager.mjs'
|
||||||
|
import { isProfessionalGroupPlan } from '../Subscription/PlansHelper.mjs'
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
import AuthorizationManager from '../Authorization/AuthorizationManager.mjs'
|
import AuthorizationManager from '../Authorization/AuthorizationManager.mjs'
|
||||||
import InactiveProjectManager from '../InactiveData/InactiveProjectManager.mjs'
|
import InactiveProjectManager from '../InactiveData/InactiveProjectManager.mjs'
|
||||||
@@ -932,6 +933,9 @@ const _ProjectController = {
|
|||||||
planCode,
|
planCode,
|
||||||
planName: planDetails?.name,
|
planName: planDetails?.name,
|
||||||
isAnnualPlan: planCode && planDetails?.annual,
|
isAnnualPlan: planCode && planDetails?.annual,
|
||||||
|
isProfessionalGroupPlan: Boolean(
|
||||||
|
subscription && isProfessionalGroupPlan(subscription)
|
||||||
|
),
|
||||||
isMemberOfGroupSubscription: userIsMemberOfGroupSubscription,
|
isMemberOfGroupSubscription: userIsMemberOfGroupSubscription,
|
||||||
hasInstitutionLicence: userHasInstitutionLicence,
|
hasInstitutionLicence: userHasInstitutionLicence,
|
||||||
},
|
},
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import OLButton from '@/shared/components/ol/ol-button'
|
||||||
|
import getMeta from '@/utils/meta'
|
||||||
|
|
||||||
|
export default function GiveFeedbackLink() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const isProfessionalGroupPlan = getMeta('ol-user')?.isProfessionalGroupPlan
|
||||||
|
|
||||||
|
const link = isProfessionalGroupPlan
|
||||||
|
? 'https://forms.gle/rz1JDMuNajWG4ZY49'
|
||||||
|
: 'https://forms.gle/WLEjzG4Ayp8zFscM9'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OLButton
|
||||||
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
href={link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="fw-bold"
|
||||||
|
>
|
||||||
|
{t('give_feedback')}
|
||||||
|
</OLButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
+3
-2
@@ -15,6 +15,7 @@ import OLButton from '@/shared/components/ol/ol-button'
|
|||||||
import OLSpinner from '@/shared/components/ol/ol-spinner'
|
import OLSpinner from '@/shared/components/ol/ol-spinner'
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
import ErrorMessage from '@/features/share-project-modal/components/error-message'
|
import ErrorMessage from '@/features/share-project-modal/components/error-message'
|
||||||
|
import GiveFeedbackLink from '@/features/share-project-modal/components/give-feedback-link'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||||
import { useShareProjectContext } from '@/features/share-project-modal/components/share-project-modal'
|
import { useShareProjectContext } from '@/features/share-project-modal/components/share-project-modal'
|
||||||
@@ -49,8 +50,7 @@ export default function ShareProjectModalContent({
|
|||||||
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
const isSharingUpdatesEnabled = useFeatureFlag('sharing-updates')
|
||||||
const [isInvitedPeopleScreen, setIsInvitedPeopleScreen] = useState(false)
|
const [isInvitedPeopleScreen, setIsInvitedPeopleScreen] = useState(false)
|
||||||
const { successActionMessage } = useShareProjectContext()
|
const { successActionMessage } = useShareProjectContext()
|
||||||
|
const { isRestrictedTokenMember, isProjectOwner } = useEditorContext()
|
||||||
const { isRestrictedTokenMember } = useEditorContext()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OLModal show={show} onHide={cancel} animation={animation}>
|
<OLModal show={show} onHide={cancel} animation={animation}>
|
||||||
@@ -71,6 +71,7 @@ export default function ShareProjectModalContent({
|
|||||||
: t('share_project')}
|
: t('share_project')}
|
||||||
</OLModalTitle>
|
</OLModalTitle>
|
||||||
)}
|
)}
|
||||||
|
{isSharingUpdatesEnabled && isProjectOwner && <GiveFeedbackLink />}
|
||||||
</div>
|
</div>
|
||||||
</OLModalHeader>
|
</OLModalHeader>
|
||||||
|
|
||||||
|
|||||||
+68
@@ -1053,6 +1053,15 @@ describe('<ShareProjectModal/>', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not show the "Give feedback" link when the "sharing-updates" feature flag is disabled', async function () {
|
||||||
|
renderWithEditorContext(
|
||||||
|
<ShareProjectModal {...modalProps} />,
|
||||||
|
createContextProps()
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.queryByRole('link', { name: 'Give feedback' })).to.be.null
|
||||||
|
})
|
||||||
|
|
||||||
describe('with "sharing-updates" feature flag', function () {
|
describe('with "sharing-updates" feature flag', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||||
@@ -1174,5 +1183,64 @@ describe('<ShareProjectModal/>', function () {
|
|||||||
|
|
||||||
await screen.findByText('Invitation(s) sent.')
|
await screen.findByText('Invitation(s) sent.')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows the "Give feedback" link for the project owner', async function () {
|
||||||
|
renderWithEditorContext(
|
||||||
|
<ShareProjectModal {...modalProps} />,
|
||||||
|
createContextProps()
|
||||||
|
)
|
||||||
|
|
||||||
|
await screen.findByRole('link', { name: 'Give feedback' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not show the "Give feedback" link for non-owners', async function () {
|
||||||
|
renderWithEditorContext(<ShareProjectModal {...modalProps} />, {
|
||||||
|
...createContextProps(),
|
||||||
|
user: {
|
||||||
|
id: 'non-project-owner',
|
||||||
|
email: 'non-project-owner@example.com',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(screen.queryByRole('link', { name: 'Give feedback' })).to.be.null
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('"Give feedback" link URL based on subscription plan', function () {
|
||||||
|
it('links to the professional feedback URL when the user has a professional group plan', async function () {
|
||||||
|
renderWithEditorContext(<ShareProjectModal {...modalProps} />, {
|
||||||
|
...createContextProps(),
|
||||||
|
user: {
|
||||||
|
id: USER_ID,
|
||||||
|
email: USER_EMAIL,
|
||||||
|
isProfessionalGroupPlan: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const feedbackLink = await screen.findByRole('link', {
|
||||||
|
name: 'Give feedback',
|
||||||
|
})
|
||||||
|
expect(feedbackLink.getAttribute('href')).to.equal(
|
||||||
|
'https://forms.gle/rz1JDMuNajWG4ZY49'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to the standard feedback URL when the user does not have a professional group plan', async function () {
|
||||||
|
renderWithEditorContext(<ShareProjectModal {...modalProps} />, {
|
||||||
|
...createContextProps(),
|
||||||
|
user: {
|
||||||
|
id: USER_ID,
|
||||||
|
email: USER_EMAIL,
|
||||||
|
isProfessionalGroupPlan: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const feedbackLink = await screen.findByRole('link', {
|
||||||
|
name: 'Give feedback',
|
||||||
|
})
|
||||||
|
expect(feedbackLink.getAttribute('href')).to.equal(
|
||||||
|
'https://forms.gle/WLEjzG4Ayp8zFscM9'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -70,7 +70,12 @@ const defaultUserSettings = {
|
|||||||
} satisfies UserSettings
|
} satisfies UserSettings
|
||||||
|
|
||||||
export type EditorProvidersProps = {
|
export type EditorProvidersProps = {
|
||||||
user?: { id: string; email: string; signUpDate?: string }
|
user?: {
|
||||||
|
id: string
|
||||||
|
email: string
|
||||||
|
signUpDate?: string
|
||||||
|
isProfessionalGroupPlan?: boolean
|
||||||
|
}
|
||||||
projectId?: string
|
projectId?: string
|
||||||
projectName?: string
|
projectName?: string
|
||||||
projectOwner?: ProjectMetadata['owner']
|
projectOwner?: ProjectMetadata['owner']
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export type User = {
|
|||||||
planName?: string
|
planName?: string
|
||||||
isAnnualPlan?: boolean
|
isAnnualPlan?: boolean
|
||||||
isMemberOfGroupSubscription?: boolean
|
isMemberOfGroupSubscription?: boolean
|
||||||
|
isProfessionalGroupPlan?: boolean
|
||||||
hasInstitutionLicence?: boolean
|
hasInstitutionLicence?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user