first commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import getMeta from '@/utils/meta'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function AcceptedInvite() {
|
||||
const { t } = useTranslation()
|
||||
const inviterName = getMeta('ol-inviterName')
|
||||
const groupSSOActive = getMeta('ol-groupSSOActive')
|
||||
const subscriptionId = getMeta('ol-subscriptionId')
|
||||
|
||||
const doneLink = groupSSOActive
|
||||
? `/subscription/${subscriptionId}/sso_enrollment`
|
||||
: '/project'
|
||||
|
||||
return (
|
||||
<div className="text-center">
|
||||
<p>{t('joined_team', { inviterName })}</p>
|
||||
<p>
|
||||
<a href={doneLink} className="btn btn-primary">
|
||||
{t('done')}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import useWaitForI18n from '@/shared/hooks/use-wait-for-i18n'
|
||||
import getMeta from '@/utils/meta'
|
||||
import HasIndividualRecurlySubscription from './has-individual-recurly-subscription'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import ManagedUserCannotJoin from './managed-user-cannot-join'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import JoinGroup from './join-group'
|
||||
import AcceptedInvite from './accepted-invite'
|
||||
import OLRow from '@/features/ui/components/ol/ol-row'
|
||||
import OLCol from '@/features/ui/components/ol/ol-col'
|
||||
import OLPageContentCard from '@/features/ui/components/ol/ol-page-content-card'
|
||||
|
||||
export type InviteViewTypes =
|
||||
| 'invite'
|
||||
| 'invite-accepted'
|
||||
| 'cancel-personal-subscription'
|
||||
| 'managed-user-cannot-join'
|
||||
| undefined
|
||||
|
||||
function GroupInviteViews() {
|
||||
const hasIndividualRecurlySubscription = getMeta(
|
||||
'ol-hasIndividualRecurlySubscription'
|
||||
)
|
||||
const cannotJoinSubscription = getMeta('ol-cannot-join-subscription')
|
||||
|
||||
useEffect(() => {
|
||||
if (cannotJoinSubscription) {
|
||||
setView('managed-user-cannot-join')
|
||||
} else if (hasIndividualRecurlySubscription) {
|
||||
setView('cancel-personal-subscription')
|
||||
} else {
|
||||
setView('invite')
|
||||
}
|
||||
}, [cannotJoinSubscription, hasIndividualRecurlySubscription])
|
||||
const [view, setView] = useState<InviteViewTypes>(undefined)
|
||||
|
||||
if (!view) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (view === 'managed-user-cannot-join') {
|
||||
return <ManagedUserCannotJoin />
|
||||
} else if (view === 'cancel-personal-subscription') {
|
||||
return <HasIndividualRecurlySubscription setView={setView} />
|
||||
} else if (view === 'invite') {
|
||||
return <JoinGroup setView={setView} />
|
||||
} else if (view === 'invite-accepted') {
|
||||
return <AcceptedInvite />
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default function GroupInvite() {
|
||||
const inviterName = getMeta('ol-inviterName')
|
||||
const expired = getMeta('ol-expired')
|
||||
const { isReady } = useWaitForI18n()
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (!isReady) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container" id="main-content">
|
||||
{expired && (
|
||||
<OLRow>
|
||||
<OLCol lg={{ span: 8, offset: 2 }}>
|
||||
<Notification type="error" content={t('email_link_expired')} />
|
||||
</OLCol>
|
||||
</OLRow>
|
||||
)}
|
||||
|
||||
<OLRow className="row row-spaced">
|
||||
<OLCol lg={{ span: 8, offset: 2 }}>
|
||||
<OLPageContentCard>
|
||||
<div className="page-header">
|
||||
<h1 className="text-center">
|
||||
<Trans
|
||||
i18nKey="invited_to_group"
|
||||
values={{ inviterName }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={
|
||||
/* eslint-disable-next-line react/jsx-key */
|
||||
[<span className="team-invite-name" />]
|
||||
}
|
||||
/>
|
||||
</h1>
|
||||
</div>
|
||||
<GroupInviteViews />
|
||||
</OLPageContentCard>
|
||||
</OLCol>
|
||||
</OLRow>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { FetchError, postJSON } from '@/infrastructure/fetch-json'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import useAsync from '@/shared/hooks/use-async'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { Dispatch, SetStateAction, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { InviteViewTypes } from './group-invite'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
|
||||
export default function HasIndividualRecurlySubscription({
|
||||
setView,
|
||||
}: {
|
||||
setView: Dispatch<SetStateAction<InviteViewTypes>>
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
runAsync,
|
||||
isLoading: isCancelling,
|
||||
isError,
|
||||
} = useAsync<never, FetchError>()
|
||||
|
||||
const cancelPersonalSubscription = useCallback(() => {
|
||||
runAsync(
|
||||
postJSON('/user/subscription/cancel', {
|
||||
body: {
|
||||
_csrf: getMeta('ol-csrfToken'),
|
||||
},
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
setView('invite')
|
||||
})
|
||||
.catch(debugConsole.error)
|
||||
}, [runAsync, setView])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isError && (
|
||||
<Notification
|
||||
type="error"
|
||||
content={t('something_went_wrong_canceling_your_subscription')}
|
||||
className="my-3"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="text-center">
|
||||
<p>{t('cancel_personal_subscription_first')}</p>
|
||||
<p>
|
||||
<OLButton
|
||||
variant="secondary"
|
||||
disabled={isCancelling}
|
||||
onClick={() => setView('invite')}
|
||||
>
|
||||
{t('not_now')}
|
||||
</OLButton>
|
||||
|
||||
<OLButton
|
||||
variant="primary"
|
||||
disabled={isCancelling}
|
||||
onClick={() => cancelPersonalSubscription()}
|
||||
>
|
||||
{t('cancel_your_subscription')}
|
||||
</OLButton>
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Dispatch, SetStateAction, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { InviteViewTypes } from './group-invite'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { FetchError, putJSON } from '@/infrastructure/fetch-json'
|
||||
import useAsync from '@/shared/hooks/use-async'
|
||||
import classNames from 'classnames'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
|
||||
export default function JoinGroup({
|
||||
setView,
|
||||
}: {
|
||||
setView: Dispatch<SetStateAction<InviteViewTypes>>
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const expired = getMeta('ol-expired')
|
||||
const inviteToken = getMeta('ol-inviteToken')
|
||||
const {
|
||||
runAsync,
|
||||
isLoading: isJoining,
|
||||
isError,
|
||||
} = useAsync<never, FetchError>()
|
||||
|
||||
const notNowBtnClasses = classNames(
|
||||
'btn',
|
||||
'btn-secondary',
|
||||
isJoining ? 'disabled' : ''
|
||||
)
|
||||
|
||||
const joinTeam = useCallback(() => {
|
||||
runAsync(putJSON(`/subscription/invites/${inviteToken}`))
|
||||
.then(() => {
|
||||
setView('invite-accepted')
|
||||
})
|
||||
.catch(debugConsole.error)
|
||||
}, [inviteToken, runAsync, setView])
|
||||
|
||||
if (!inviteToken) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isError && (
|
||||
<Notification
|
||||
type="error"
|
||||
content={t('generic_something_went_wrong')}
|
||||
className="my-3"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="text-center">
|
||||
<p>{t('join_team_explanation')}</p>
|
||||
{!expired && (
|
||||
<p>
|
||||
<a className={notNowBtnClasses} href="/project">
|
||||
{t('not_now')}
|
||||
</a>
|
||||
|
||||
<OLButton
|
||||
variant="primary"
|
||||
onClick={() => joinTeam()}
|
||||
disabled={isJoining}
|
||||
>
|
||||
{t('accept_invitation')}
|
||||
</OLButton>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
export default function ManagedUserCannotJoin() {
|
||||
const { t } = useTranslation()
|
||||
const currentManagedUserAdminEmail = getMeta(
|
||||
'ol-currentManagedUserAdminEmail'
|
||||
)
|
||||
|
||||
return (
|
||||
<Notification
|
||||
type="info"
|
||||
title={t('you_cant_join_this_group_subscription')}
|
||||
content={
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="your_account_is_managed_by_admin_cant_join_additional_group"
|
||||
values={{ admin: currentManagedUserAdminEmail }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={[
|
||||
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
|
||||
<a href="/learn/how-to/Understanding_Managed_Overleaf_Accounts" />,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user