mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
fix: replace /stripe/subscription requests
This commit is contained in:
1 parent
d3676710f9
commit
028a8a093f
6 files changed
+39
-167
No files matched your search
@@ -12,4 +12,5 @@ export interface StripeProduct {
|
||||
name: string
|
||||
prod_id: string
|
||||
unit_amount: number
|
||||
supabase_prod_id: string
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
import Link from 'next/link'
|
||||
import dayjs from 'dayjs'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import { FC, useState, useEffect } from 'react'
|
||||
import { FC, useEffect } from 'react'
|
||||
import { IconChevronRight, IconLoader } from '@supabase/ui'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { useProjectSubscription, useStore } from 'hooks'
|
||||
import Panel from 'components/to-be-cleaned/Panel'
|
||||
import { StripeSubscription } from 'components/interfaces/Billing'
|
||||
|
||||
dayjs.extend(utc)
|
||||
|
||||
@@ -18,35 +15,19 @@ interface ProjectSummaryProps {
|
||||
|
||||
const ProjectSummary: FC<ProjectSummaryProps> = ({ project }) => {
|
||||
const { ui } = useStore()
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [subscription, setSubscription] = useState<StripeSubscription>()
|
||||
const { subscription, isLoading: loading, error } = useProjectSubscription(project.ref)
|
||||
|
||||
const currentPeriodStart = subscription?.billing?.current_period_start ?? 0
|
||||
const currentPeriodEnd = subscription?.billing?.current_period_end ?? 0
|
||||
|
||||
useEffect(() => {
|
||||
getSubscription()
|
||||
}, [])
|
||||
|
||||
const getSubscription = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const { data: subscription, error }: { data: StripeSubscription; error: any } = await post(
|
||||
`${API_URL}/stripe/subscription`,
|
||||
{ subscription_id: project.subscription_id }
|
||||
)
|
||||
if (error) throw error
|
||||
setSubscription(subscription)
|
||||
} catch (error: any) {
|
||||
if (error) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to get project subscription: ${error.message}`,
|
||||
message: `Failed to get project subscription: ${error?.message ?? 'unknown'}`,
|
||||
})
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}, [error])
|
||||
|
||||
return (
|
||||
<div className="w-full px-6 py-3 flex items-center">
|
||||
|
||||
@@ -2,8 +2,8 @@ import React, { FC, useEffect, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { Loading, Typography } from '@supabase/ui'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useProjectSubscription, useStore } from 'hooks'
|
||||
import { API_URL, PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
|
||||
import { get, post } from 'lib/common/fetch'
|
||||
import SparkBar from 'components/ui/SparkBar'
|
||||
|
||||
@@ -193,45 +193,19 @@ const usageLimits = {
|
||||
const ProjectUsage: FC<any> = ({ projectRef, subscription_id }) => {
|
||||
const { ui } = useStore()
|
||||
const { data: stats, error: usageError } = useSWR(`${API_URL}/projects/${projectRef}/usage`, get)
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [error, setError] = useState<any>(null)
|
||||
const [subscription, setSubscription] = useState<any>(null)
|
||||
const { subscription, isLoading: loading, error } = useProjectSubscription(projectRef)
|
||||
|
||||
useEffect(() => {
|
||||
let cancel = false
|
||||
|
||||
/**
|
||||
* Get subscription information to decide
|
||||
*/
|
||||
const getSubscription = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
const { data, error } = await post(`${API_URL}/stripe/subscription`, {
|
||||
subscription_id: subscription_id,
|
||||
})
|
||||
if (!cancel) setSubscription(data)
|
||||
if (error) throw error
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to get subscription: ${error.message}`,
|
||||
})
|
||||
if (!cancel) setError(error)
|
||||
} finally {
|
||||
if (!cancel) setLoading(false)
|
||||
}
|
||||
if (error) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to get project subscription: ${error?.message ?? 'unknown'}`,
|
||||
})
|
||||
}
|
||||
}, [error])
|
||||
|
||||
getSubscription()
|
||||
|
||||
return () => {
|
||||
cancel = true
|
||||
}
|
||||
}, [subscription_id])
|
||||
|
||||
const tier = subscription && subscription.tier.unit_amount > 0 ? 'pro' : 'free'
|
||||
const tier =
|
||||
subscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.PRO ? 'pro' : 'free'
|
||||
|
||||
return (
|
||||
<Loading active={loading}>
|
||||
@@ -296,41 +270,10 @@ export default ProjectUsage
|
||||
|
||||
export const ProjectUsageMinimal: FC<any> = ({ projectRef, subscription_id, filter }) => {
|
||||
const { data: stats, error: usageError } = useSWR(`${API_URL}/projects/${projectRef}/usage`, get)
|
||||
const { subscription, isLoading: loading, error } = useProjectSubscription(projectRef)
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [error, setError] = useState<any>(null)
|
||||
const [subscription, setSubscription] = useState<any>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let cancel = false
|
||||
|
||||
/**
|
||||
* Get subscription information to decide
|
||||
*/
|
||||
const getSubscription = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
const { data, error } = await post(`${API_URL}/stripe/subscription`, {
|
||||
subscription_id: subscription_id,
|
||||
})
|
||||
if (!cancel) setSubscription(data)
|
||||
if (error) throw error
|
||||
} catch (error: any) {
|
||||
if (!cancel) setError(error)
|
||||
} finally {
|
||||
if (!cancel) setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
getSubscription()
|
||||
|
||||
return () => {
|
||||
cancel = true
|
||||
}
|
||||
}, [subscription_id])
|
||||
|
||||
const tier = subscription && subscription.tier.unit_amount > 0 ? 'pro' : 'free'
|
||||
const tier =
|
||||
subscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.PRO ? 'pro' : 'free'
|
||||
|
||||
return (
|
||||
<Loading active={loading}>
|
||||
|
||||
@@ -3,3 +3,5 @@ export * from './useOrganizationDetail'
|
||||
export * from './useProfile'
|
||||
export * from './useProjectAuthConfig'
|
||||
export * from './useSubscriptionStats'
|
||||
export * from './useProjectSubscription'
|
||||
export * from './useProjectPaygStatistics'
|
||||
@@ -28,6 +28,7 @@ export const PRICING_TIER_LABELS = {
|
||||
export const PRICING_TIER_PRODUCT_IDS = {
|
||||
FREE: 'tier_free',
|
||||
PRO: 'tier_pro',
|
||||
PAYG: 'tier_payg',
|
||||
}
|
||||
|
||||
export const PRICING_TIER_FREE_KEY = 'FREE'
|
||||
|
||||
@@ -2,27 +2,12 @@ import dayjs from 'dayjs'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { Typography, Loading, IconArrowRight } from '@supabase/ui'
|
||||
import { get as _get, maxBy } from 'lodash'
|
||||
import { Dictionary } from '@supabase/grid'
|
||||
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { post, get } from 'lib/common/fetch'
|
||||
import {
|
||||
API_URL,
|
||||
DATE_FORMAT,
|
||||
STRIPE_PRODUCT_IDS,
|
||||
TIME_PERIODS_REPORTS,
|
||||
TIME_PERIODS_BILLING,
|
||||
} from 'lib/constants'
|
||||
import { useProjectPaygStatistics, useProjectSubscription, useStore, withAuth } from 'hooks'
|
||||
import { STRIPE_PRODUCT_IDS, TIME_PERIODS_REPORTS, TIME_PERIODS_BILLING } from 'lib/constants'
|
||||
import { SettingsLayout } from 'components/layouts'
|
||||
import LoadingUI from 'components/ui/Loading'
|
||||
import {
|
||||
PAYGUsage,
|
||||
Subscription,
|
||||
StripeSubscription,
|
||||
chargeableProducts,
|
||||
Invoices,
|
||||
} from 'components/interfaces/Billing'
|
||||
import { PAYGUsage, Subscription, Invoices } from 'components/interfaces/Billing'
|
||||
|
||||
import ProjectUsage from 'components/to-be-cleaned/Usage'
|
||||
import DateRangePicker from 'components/to-be-cleaned/DateRangePicker'
|
||||
@@ -50,66 +35,25 @@ type SettingsProps = {
|
||||
}
|
||||
const Settings: FC<SettingsProps> = ({ project }) => {
|
||||
const { ui } = useStore()
|
||||
const projectRef = ui.selectedProject?.ref
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
const [subscription, setSubscription] = useState<StripeSubscription>()
|
||||
const [paygStats, setPaygStats] = useState<Dictionary<number>>()
|
||||
const {
|
||||
subscription,
|
||||
isLoading: loading,
|
||||
error,
|
||||
} = useProjectSubscription(ui.selectedProject?.ref)
|
||||
const { paygStats } = useProjectPaygStatistics(
|
||||
ui.selectedProject?.ref,
|
||||
subscription?.tier?.supabase_prod_id
|
||||
)
|
||||
const [dateRange, setDateRange] = useState<any>()
|
||||
|
||||
useEffect(() => {
|
||||
if (projectRef) {
|
||||
getSubscription()
|
||||
}
|
||||
}, [projectRef])
|
||||
|
||||
const getSubscription = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const { data: subscription, error }: { data: StripeSubscription; error: any } = await post(
|
||||
`${API_URL}/stripe/subscription`,
|
||||
{
|
||||
subscription_id: project.subscription_id,
|
||||
}
|
||||
)
|
||||
if (error) throw error
|
||||
setSubscription(subscription)
|
||||
|
||||
if (subscription.tier.prod_id === STRIPE_PRODUCT_IDS.PAYG) {
|
||||
fetchPaygStatistics()
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error) {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to get subscription: ${error.message}`,
|
||||
message: `Failed to get project subscription: ${error?.message ?? 'unknown'}`,
|
||||
})
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchPaygStatistics = async () => {
|
||||
const startDate = dayjs().utc().startOf('month').format(DATE_FORMAT)
|
||||
const endDate = dayjs().utc().endOf('month').format(DATE_FORMAT)
|
||||
const attributes =
|
||||
'total_db_size_bytes,total_db_egress_bytes,total_storage_size_bytes,total_storage_egress'
|
||||
const url = `${API_URL}/projects/${
|
||||
project.ref
|
||||
}/daily-stats?attribute=${attributes}&startDate=${encodeURIComponent(
|
||||
startDate
|
||||
)}&endDate=${encodeURIComponent(endDate)}&interval='1d'`
|
||||
|
||||
const { data } = await get(url)
|
||||
|
||||
const paygStats: any = {}
|
||||
chargeableProducts.forEach((product: any) => {
|
||||
product.features.forEach((feature: any) => {
|
||||
paygStats[feature.attribute] = _get(maxBy(data, feature.attribute), feature.attribute)
|
||||
})
|
||||
})
|
||||
setPaygStats(paygStats)
|
||||
}
|
||||
}, [error])
|
||||
|
||||
if (!subscription) {
|
||||
return <LoadingUI />
|
||||
|
||||
Reference in new issue
Block a user