From 8eacf1380689090c4ece29a0dec98712d3330f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Leszczyk?= Date: Fri, 4 Mar 2022 12:01:35 +0100 Subject: [PATCH] feat(dashboard-v2): introduce PlansProvider --- .../src/contexts/plans/PlansContext.js | 7 +++ .../src/contexts/plans/PlansProvider.js | 47 +++++++++++++++++++ .../dashboard-v2/src/contexts/plans/index.js | 2 + .../src/contexts/plans/usePlans.js | 5 ++ 4 files changed, 61 insertions(+) create mode 100644 packages/dashboard-v2/src/contexts/plans/PlansContext.js create mode 100644 packages/dashboard-v2/src/contexts/plans/PlansProvider.js create mode 100644 packages/dashboard-v2/src/contexts/plans/index.js create mode 100644 packages/dashboard-v2/src/contexts/plans/usePlans.js diff --git a/packages/dashboard-v2/src/contexts/plans/PlansContext.js b/packages/dashboard-v2/src/contexts/plans/PlansContext.js new file mode 100644 index 00000000..ff35b45e --- /dev/null +++ b/packages/dashboard-v2/src/contexts/plans/PlansContext.js @@ -0,0 +1,7 @@ +import { createContext } from "react"; + +export const PlansContext = createContext({ + plans: [], + limits: [], + error: null, +}); diff --git a/packages/dashboard-v2/src/contexts/plans/PlansProvider.js b/packages/dashboard-v2/src/contexts/plans/PlansProvider.js new file mode 100644 index 00000000..c481e296 --- /dev/null +++ b/packages/dashboard-v2/src/contexts/plans/PlansProvider.js @@ -0,0 +1,47 @@ +import { useEffect, useState } from "react"; +import useSWR from "swr"; + +import freePlan from "../../lib/tiers"; + +import { PlansContext } from "./PlansContext"; + +/** + * NOTE: this function heavily relies on the fact that each Plan's `tier` + * property corresponds to the plan's index in UserLimits array in + * skynet-accounts code. + * + * @see https://github.com/SkynetLabs/skynet-accounts/blob/7337e740b71b77e6d08016db801e293b8ad81abc/database/user.go#L53-L101 + */ +const aggregatePlansAndLimits = (plans, limits) => { + const sortedPlans = [freePlan, ...plans].sort((planA, planB) => planA.tier - planB.tier); + + // Decorate each plan with its corresponding limits data, if available. + if (limits?.length) { + return sortedPlans.map((plan) => ({ ...plan, limits: limits[plan.tier] || null })); + } + + // If we don't have the limits data yet, set just return the plans. + + return sortedPlans; +}; + +export const PlansProvider = ({ children }) => { + const { data: rawPlans, error: plansError } = useSWR("stripe/prices"); + const { data: limits, error: limitsError } = useSWR("limits"); + + const [plans, setPlans] = useState([freePlan]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + if (plansError || limitsError) { + setLoading(false); + setError(plansError || limitsError); + } else if (rawPlans) { + setLoading(false); + setPlans(aggregatePlansAndLimits(rawPlans, limits?.userLimits)); + } + }, [rawPlans, limits, plansError, limitsError]); + + return {children}; +}; diff --git a/packages/dashboard-v2/src/contexts/plans/index.js b/packages/dashboard-v2/src/contexts/plans/index.js new file mode 100644 index 00000000..84dd790f --- /dev/null +++ b/packages/dashboard-v2/src/contexts/plans/index.js @@ -0,0 +1,2 @@ +export * from "./PlansProvider"; +export * from "./usePlans"; diff --git a/packages/dashboard-v2/src/contexts/plans/usePlans.js b/packages/dashboard-v2/src/contexts/plans/usePlans.js new file mode 100644 index 00000000..f36e8595 --- /dev/null +++ b/packages/dashboard-v2/src/contexts/plans/usePlans.js @@ -0,0 +1,5 @@ +import { useContext } from "react"; + +import { PlansContext } from "./PlansContext"; + +export const usePlans = () => useContext(PlansContext);