subscription-dashboard-context.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {
  2. createContext,
  3. ReactNode,
  4. useContext,
  5. useEffect,
  6. useMemo,
  7. useState,
  8. } from 'react'
  9. import {
  10. ManagedGroupSubscription,
  11. Subscription,
  12. } from '../../../../../types/subscription/dashboard/subscription'
  13. import { Plan } from '../../../../../types/subscription/plan'
  14. import { Institution } from '../../../../../types/institution'
  15. import getMeta from '../../../utils/meta'
  16. import { loadDisplayPriceWithTaxPromise } from '../util/recurly-pricing'
  17. import { isRecurlyLoaded } from '../util/is-recurly-loaded'
  18. type SubscriptionDashboardContextValue = {
  19. hasDisplayedSubscription: boolean
  20. institutionMemberships?: Array<Institution>
  21. managedGroupSubscriptions: Array<ManagedGroupSubscription>
  22. personalSubscription?: Subscription
  23. plans: Array<Plan>
  24. queryingIndividualPlansData: boolean
  25. recurlyLoadError: boolean
  26. setRecurlyLoadError: React.Dispatch<React.SetStateAction<boolean>>
  27. showCancellation: boolean
  28. setShowCancellation: React.Dispatch<React.SetStateAction<boolean>>
  29. showChangePersonalPlan: boolean
  30. setShowChangePersonalPlan: React.Dispatch<React.SetStateAction<boolean>>
  31. }
  32. export const SubscriptionDashboardContext = createContext<
  33. SubscriptionDashboardContextValue | undefined
  34. >(undefined)
  35. export function SubscriptionDashboardProvider({
  36. children,
  37. }: {
  38. children: ReactNode
  39. }) {
  40. const [recurlyLoadError, setRecurlyLoadError] = useState(false)
  41. const [showCancellation, setShowCancellation] = useState(false)
  42. const [showChangePersonalPlan, setShowChangePersonalPlan] = useState(false)
  43. const [plans, setPlans] = useState([])
  44. const [queryingIndividualPlansData, setQueryingIndividualPlansData] =
  45. useState(true)
  46. const plansWithoutDisplayPrice = getMeta('ol-plans')
  47. const institutionMemberships = getMeta('ol-currentInstitutionsWithLicence')
  48. const personalSubscription = getMeta('ol-subscription')
  49. const managedGroupSubscriptions = getMeta('ol-managedGroupSubscriptions')
  50. const recurlyApiKey = getMeta('ol-recurlyApiKey')
  51. const hasDisplayedSubscription =
  52. institutionMemberships?.length > 0 ||
  53. personalSubscription ||
  54. managedGroupSubscriptions?.length > 0
  55. useEffect(() => {
  56. if (!isRecurlyLoaded()) {
  57. setRecurlyLoadError(true)
  58. } else if (recurlyApiKey) {
  59. recurly.configure(recurlyApiKey)
  60. }
  61. }, [recurlyApiKey, setRecurlyLoadError])
  62. useEffect(() => {
  63. if (isRecurlyLoaded() && plansWithoutDisplayPrice && personalSubscription) {
  64. const { currency, taxRate } = personalSubscription.recurly
  65. const fetchPlansDisplayPrices = async () => {
  66. for (const plan of plansWithoutDisplayPrice) {
  67. try {
  68. const priceData = await loadDisplayPriceWithTaxPromise(
  69. plan.planCode,
  70. currency,
  71. taxRate
  72. )
  73. if (priceData?.totalForDisplay) {
  74. plan.displayPrice = priceData.totalForDisplay
  75. }
  76. } catch (error) {
  77. console.error(error)
  78. }
  79. }
  80. setPlans(plansWithoutDisplayPrice)
  81. setQueryingIndividualPlansData(false)
  82. }
  83. fetchPlansDisplayPrices().catch(console.error)
  84. }
  85. }, [personalSubscription, plansWithoutDisplayPrice])
  86. const value = useMemo<SubscriptionDashboardContextValue>(
  87. () => ({
  88. hasDisplayedSubscription,
  89. institutionMemberships,
  90. managedGroupSubscriptions,
  91. personalSubscription,
  92. plans,
  93. queryingIndividualPlansData,
  94. recurlyLoadError,
  95. setRecurlyLoadError,
  96. showCancellation,
  97. setShowCancellation,
  98. showChangePersonalPlan,
  99. setShowChangePersonalPlan,
  100. }),
  101. [
  102. hasDisplayedSubscription,
  103. institutionMemberships,
  104. managedGroupSubscriptions,
  105. personalSubscription,
  106. plans,
  107. queryingIndividualPlansData,
  108. recurlyLoadError,
  109. setRecurlyLoadError,
  110. showCancellation,
  111. setShowCancellation,
  112. showChangePersonalPlan,
  113. setShowChangePersonalPlan,
  114. ]
  115. )
  116. return (
  117. <SubscriptionDashboardContext.Provider value={value}>
  118. {children}
  119. </SubscriptionDashboardContext.Provider>
  120. )
  121. }
  122. export function useSubscriptionDashboardContext() {
  123. const context = useContext(SubscriptionDashboardContext)
  124. if (!context) {
  125. throw new Error(
  126. 'SubscriptionDashboardContext is only available inside SubscriptionDashboardProvider'
  127. )
  128. }
  129. return context
  130. }