overleaf/services/web/frontend/js/features/subscription/context/subscription-dashboard-context.tsx

236 lines
7.3 KiB
TypeScript
Raw Normal View History

import {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
import {
ManagedGroupSubscription,
Subscription,
} from '../../../../../types/subscription/dashboard/subscription'
import { Plan } from '../../../../../types/subscription/plan'
import { Institution as ManagedInstitution } from '../components/dashboard/managed-institutions'
import { Institution } from '../../../../../types/institution'
import getMeta from '../../../utils/meta'
import { loadDisplayPriceWithTaxPromise } from '../util/recurly-pricing'
import { isRecurlyLoaded } from '../util/is-recurly-loaded'
import { SubscriptionDashModalIds } from '../../../../../types/subscription/dashboard/modal-ids'
type SubscriptionDashboardContextValue = {
groupPlanToChangeToCode?: string
groupPlanToChangeToSize: string
groupPlanToChangeToUsage?: string
handleCloseModal: () => void
handleOpenModal: (
modalIdToOpen: SubscriptionDashModalIds,
planCode?: string
) => void
hasDisplayedSubscription: boolean
institutionMemberships?: Institution[]
managedGroupSubscriptions: ManagedGroupSubscription[]
managedInstitutions: ManagedInstitution[]
updateManagedInstitution: (institution: ManagedInstitution) => void
modalIdShown?: SubscriptionDashModalIds
personalSubscription?: Subscription
plans: Plan[]
planCodeToChangeTo?: string
queryingIndividualPlansData: boolean
recurlyLoadError: boolean
setGroupPlanToChangeToCode: React.Dispatch<
React.SetStateAction<string | undefined>
>
setGroupPlanToChangeToSize: React.Dispatch<React.SetStateAction<string>>
setGroupPlanToChangeToUsage: React.Dispatch<React.SetStateAction<string>>
setModalIdShown: React.Dispatch<
React.SetStateAction<SubscriptionDashModalIds | undefined>
>
setPlanCodeToChangeTo: React.Dispatch<
React.SetStateAction<string | undefined>
>
setRecurlyLoadError: React.Dispatch<React.SetStateAction<boolean>>
showCancellation: boolean
setShowCancellation: React.Dispatch<React.SetStateAction<boolean>>
showChangePersonalPlan: boolean
setShowChangePersonalPlan: React.Dispatch<React.SetStateAction<boolean>>
}
export const SubscriptionDashboardContext = createContext<
SubscriptionDashboardContextValue | undefined
>(undefined)
export function SubscriptionDashboardProvider({
children,
}: {
children: ReactNode
}) {
const [modalIdShown, setModalIdShown] = useState<
SubscriptionDashModalIds | undefined
>()
const [recurlyLoadError, setRecurlyLoadError] = useState(false)
const [showCancellation, setShowCancellation] = useState(false)
const [showChangePersonalPlan, setShowChangePersonalPlan] = useState(false)
const [plans, setPlans] = useState([])
const [queryingIndividualPlansData, setQueryingIndividualPlansData] =
useState(true)
const [planCodeToChangeTo, setPlanCodeToChangeTo] = useState<
string | undefined
>()
const [groupPlanToChangeToSize, setGroupPlanToChangeToSize] = useState('10')
const [groupPlanToChangeToCode, setGroupPlanToChangeToCode] = useState<
string | undefined
>()
const [groupPlanToChangeToUsage, setGroupPlanToChangeToUsage] =
useState('enterprise')
const plansWithoutDisplayPrice = getMeta('ol-plans')
const institutionMemberships = getMeta('ol-currentInstitutionsWithLicence')
const personalSubscription = getMeta('ol-subscription')
const managedGroupSubscriptions = getMeta('ol-managedGroupSubscriptions')
const [managedInstitutions, setManagedInstitutions] = useState<
ManagedInstitution[]
>(getMeta('ol-managedInstitutions'))
const recurlyApiKey = getMeta('ol-recurlyApiKey')
const hasDisplayedSubscription =
institutionMemberships?.length > 0 ||
personalSubscription ||
managedGroupSubscriptions?.length > 0 ||
managedInstitutions?.length > 0
useEffect(() => {
if (!isRecurlyLoaded()) {
setRecurlyLoadError(true)
} else if (recurlyApiKey) {
recurly.configure(recurlyApiKey)
}
}, [recurlyApiKey, setRecurlyLoadError])
useEffect(() => {
if (isRecurlyLoaded() && plansWithoutDisplayPrice && personalSubscription) {
const { currency, taxRate } = personalSubscription.recurly
const fetchPlansDisplayPrices = async () => {
for (const plan of plansWithoutDisplayPrice) {
try {
const priceData = await loadDisplayPriceWithTaxPromise(
plan.planCode,
currency,
taxRate
)
if (priceData?.totalForDisplay) {
plan.displayPrice = priceData.totalForDisplay
}
} catch (error) {
console.error(error)
}
}
setPlans(plansWithoutDisplayPrice)
setQueryingIndividualPlansData(false)
}
fetchPlansDisplayPrices().catch(console.error)
}
}, [personalSubscription, plansWithoutDisplayPrice])
const updateManagedInstitution = useCallback(
(institution: ManagedInstitution) => {
setManagedInstitutions(institutions => {
return [
...(institutions || []).map(i =>
i.v1Id === institution.v1Id ? institution : i
),
]
})
},
[]
)
const handleCloseModal = useCallback(() => {
setModalIdShown(undefined)
setPlanCodeToChangeTo(undefined)
}, [setModalIdShown, setPlanCodeToChangeTo])
const handleOpenModal = useCallback(
(id, planCode) => {
setModalIdShown(id)
setPlanCodeToChangeTo(planCode)
},
[setModalIdShown, setPlanCodeToChangeTo]
)
const value = useMemo<SubscriptionDashboardContextValue>(
() => ({
groupPlanToChangeToCode,
groupPlanToChangeToSize,
groupPlanToChangeToUsage,
handleCloseModal,
handleOpenModal,
hasDisplayedSubscription,
institutionMemberships,
managedGroupSubscriptions,
managedInstitutions,
updateManagedInstitution,
modalIdShown,
personalSubscription,
plans,
planCodeToChangeTo,
queryingIndividualPlansData,
recurlyLoadError,
setGroupPlanToChangeToCode,
setGroupPlanToChangeToSize,
setGroupPlanToChangeToUsage,
setModalIdShown,
setPlanCodeToChangeTo,
setRecurlyLoadError,
showCancellation,
setShowCancellation,
showChangePersonalPlan,
setShowChangePersonalPlan,
}),
[
groupPlanToChangeToCode,
groupPlanToChangeToSize,
groupPlanToChangeToUsage,
handleCloseModal,
handleOpenModal,
hasDisplayedSubscription,
institutionMemberships,
managedGroupSubscriptions,
managedInstitutions,
updateManagedInstitution,
modalIdShown,
personalSubscription,
plans,
planCodeToChangeTo,
queryingIndividualPlansData,
recurlyLoadError,
setGroupPlanToChangeToCode,
setGroupPlanToChangeToSize,
setGroupPlanToChangeToUsage,
setModalIdShown,
setPlanCodeToChangeTo,
setRecurlyLoadError,
showCancellation,
setShowCancellation,
showChangePersonalPlan,
setShowChangePersonalPlan,
]
)
return (
<SubscriptionDashboardContext.Provider value={value}>
{children}
</SubscriptionDashboardContext.Provider>
)
}
export function useSubscriptionDashboardContext() {
const context = useContext(SubscriptionDashboardContext)
if (!context) {
throw new Error(
'SubscriptionDashboardContext is only available inside SubscriptionDashboardProvider'
)
}
return context
}