From 598c1ef8669d3827129bba12f4d9cfb6cdee044a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Gr=C3=BCneberg?= Date: Mon, 4 Dec 2023 15:54:57 +0100 Subject: [PATCH] chore: remove unused billing page/queries (#19412) --- .../interfaces/Billing/Invoices.tsx | 159 ------------------ apps/studio/data/analytics/keys.ts | 25 --- .../invoices/project-invoices-count-query.ts | 43 ----- .../data/invoices/project-invoices-query.ts | 48 ------ apps/studio/data/organizations/keys.ts | 3 - .../organization-migrate-billing-mutation.ts | 76 --------- ...anization-migrate-billing-preview-query.ts | 99 ----------- 7 files changed, 453 deletions(-) delete mode 100644 apps/studio/components/interfaces/Billing/Invoices.tsx delete mode 100644 apps/studio/data/invoices/project-invoices-count-query.ts delete mode 100644 apps/studio/data/invoices/project-invoices-query.ts delete mode 100644 apps/studio/data/organizations/organization-migrate-billing-mutation.ts delete mode 100644 apps/studio/data/organizations/organization-migrate-billing-preview-query.ts diff --git a/apps/studio/components/interfaces/Billing/Invoices.tsx b/apps/studio/components/interfaces/Billing/Invoices.tsx deleted file mode 100644 index d346c37c0b1..00000000000 --- a/apps/studio/components/interfaces/Billing/Invoices.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { useParams } from 'common' -import Link from 'next/link' -import { useEffect, useState } from 'react' -import { Button, IconChevronLeft, IconChevronRight, IconDownload, IconFileText } from 'ui' - -import Table from 'components/to-be-cleaned/Table' -import AlertError from 'components/ui/AlertError' -import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' -import { getInvoice } from 'data/invoices/invoice-query' -import { useProjectInvoicesCountQuery } from 'data/invoices/project-invoices-count-query' -import { useProjectInvoicesQuery } from 'data/invoices/project-invoices-query' -import { useStore } from 'hooks' -import { InvoiceStatus } from './Invoices.types' -import InvoiceStatusBadge from './InvoiceStatusBadge' - -const PAGE_LIMIT = 10 - -const Invoices = () => { - const { ui } = useStore() - const { ref: projectRef } = useParams() - const [page, setPage] = useState(1) - - const offset = (page - 1) * PAGE_LIMIT - const { data: count, isError: isErrorCount } = useProjectInvoicesCountQuery({ projectRef }) - const { data, error, isLoading, isError, isSuccess } = useProjectInvoicesQuery({ - projectRef, - limit: PAGE_LIMIT, - offset, - }) - const invoices = data || [] - - useEffect(() => { - setPage(1) - }, [projectRef]) - - const fetchInvoice = async (id: string) => { - try { - const invoice = await getInvoice({ id }) - if (invoice?.invoice_pdf) window.open(invoice.invoice_pdf, '_blank') - } catch (error: any) { - ui.setNotification({ - category: 'info', - message: `Failed to fetch the selected invoice: ${error.message}`, - }) - } - } - - return ( -
- {isLoading && } - - {isError && } - - {isSuccess && ( - , - Date, - Amount due, - Invoice number, - - Status - , - , - ]} - body={ - invoices.length === 0 ? ( - - -

No invoices for this project yet

-
-
- ) : ( - <> - {invoices.map((x) => { - return ( - - - - - -

{new Date(x.period_end * 1000).toLocaleString()}

-
- -

- {x.subtotal >= 0 - ? `$${x.subtotal / 100}` - : `-$${Math.abs(x.subtotal / 100)}`} -

-
- -

{x.number}

-
- - - - -
- {[InvoiceStatus.UNCOLLECTIBLE, InvoiceStatus.OPEN].includes(x.status) && ( - - )} - -
-
-
- ) - })} - - -
-

- {isErrorCount - ? 'Failed to retrieve total number of invoices' - : `Showing ${offset + 1} to ${ - offset + invoices.length - } out of ${count} invoices`} -

-
-
-
-
-
- - ) - } - /> - )} - - ) -} - -export default Invoices diff --git a/apps/studio/data/analytics/keys.ts b/apps/studio/data/analytics/keys.ts index 84986a68455..4d7f028cc8c 100644 --- a/apps/studio/data/analytics/keys.ts +++ b/apps/studio/data/analytics/keys.ts @@ -57,31 +57,6 @@ export const analyticsKeys = { }, ] as const, - dailyStats: ( - projectRef: string | undefined, - { - attribute, - startDate, - endDate, - interval, - }: { - attribute?: string - startDate?: string - endDate?: string - interval?: string - } - ) => - [ - 'projects', - projectRef, - 'daily-stats', - { - attribute, - startDate: isoDateStringToDate(startDate), - endDate: isoDateStringToDate(endDate), - interval, - }, - ] as const, orgDailyStats: ( orgSlug: string | undefined, { diff --git a/apps/studio/data/invoices/project-invoices-count-query.ts b/apps/studio/data/invoices/project-invoices-count-query.ts deleted file mode 100644 index 7453d934013..00000000000 --- a/apps/studio/data/invoices/project-invoices-count-query.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query' -import { head } from 'data/fetchers' -import { ResponseError } from 'types' -import { invoicesKeys } from './keys' - -export type ProjectInvoicesCountVariables = { - projectRef?: string -} - -export async function getProjectInvoicesCount( - { projectRef }: ProjectInvoicesCountVariables, - signal?: AbortSignal -) { - if (!projectRef) throw new Error('Project ref is required') - - const res = await head(`/platform/projects/{ref}/invoices`, { - params: { path: { ref: projectRef } }, - signal, - parseAs: 'text', - }) - - if (res.error) throw (res as any).error - return Number(res.response.headers.get('X-Total-Count')) -} - -export type ProjectInvoicesCountData = Awaited> -export type ProjectInvoicesCountError = ResponseError - -export const useProjectInvoicesCountQuery = ( - { projectRef }: ProjectInvoicesCountVariables, - { - enabled = true, - ...options - }: UseQueryOptions = {} -) => - useQuery( - invoicesKeys.projectInvoicesCount(projectRef), - ({ signal }) => getProjectInvoicesCount({ projectRef }, signal), - { - enabled: enabled && typeof projectRef !== 'undefined', - ...options, - } - ) diff --git a/apps/studio/data/invoices/project-invoices-query.ts b/apps/studio/data/invoices/project-invoices-query.ts deleted file mode 100644 index 01475bf4aa5..00000000000 --- a/apps/studio/data/invoices/project-invoices-query.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query' -import { get } from 'data/fetchers' -import { ResponseError } from 'types' -import { invoicesKeys } from './keys' - -export type ProjectInvoicesVariables = { - projectRef?: string - offset?: number - limit?: number -} - -export async function getProjectInvoices( - { projectRef, offset = 0, limit = 10 }: ProjectInvoicesVariables, - signal?: AbortSignal -) { - if (!projectRef) throw new Error('Project ref is required') - - const { data, error } = await get(`/platform/projects/{ref}/invoices`, { - params: { - path: { ref: projectRef }, - query: { offset: offset.toString(), limit: limit.toString() }, - }, - signal, - }) - - if (error) throw error - return data -} - -export type ProjectInvoicesData = Awaited> -export type ProjectInvoicesError = ResponseError - -export const useProjectInvoicesQuery = ( - { projectRef, offset, limit }: ProjectInvoicesVariables, - { - enabled = true, - ...options - }: UseQueryOptions = {} -) => - // [Joshen] Switch to useInfiniteQuery - useQuery( - invoicesKeys.projectInvoices(projectRef, offset), - ({ signal }) => getProjectInvoices({ projectRef, offset, limit }, signal), - { - enabled: enabled && typeof projectRef !== 'undefined', - ...options, - } - ) diff --git a/apps/studio/data/organizations/keys.ts b/apps/studio/data/organizations/keys.ts index 682a0956d66..ff03165c3b2 100644 --- a/apps/studio/data/organizations/keys.ts +++ b/apps/studio/data/organizations/keys.ts @@ -11,9 +11,6 @@ export const organizationKeys = { slug: string | undefined, { date_start, date_end }: { date_start: string | undefined; date_end: string | undefined } ) => ['organizations', slug, 'audit-logs', { date_start, date_end }] as const, - migrateBilling: (slug: string | undefined) => ['organizations', slug, 'migrate-billing'] as const, - migrateBillingPreview: (slug: string | undefined) => - ['organizations', slug, 'migrate-billing', 'preview'] as const, subscriptionPreview: (slug: string | undefined, tier: string | undefined) => ['organizations', slug, 'subscription', 'preview', tier] as const, taxIds: (slug: string | undefined) => ['organizations', slug, 'tax-ids'] as const, diff --git a/apps/studio/data/organizations/organization-migrate-billing-mutation.ts b/apps/studio/data/organizations/organization-migrate-billing-mutation.ts deleted file mode 100644 index 12e57816bb1..00000000000 --- a/apps/studio/data/organizations/organization-migrate-billing-mutation.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' -import { toast } from 'react-hot-toast' - -import { post } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' -import { ResponseError } from 'types' -import { organizationKeys } from './keys' - -export type OrganizationBillingMigrationVariables = { - organizationSlug?: string - tier?: string - paymentMethodId?: string -} - -export async function migrateBilling({ - organizationSlug, - tier, - paymentMethodId, -}: OrganizationBillingMigrationVariables) { - if (!organizationSlug) throw new Error('organizationSlug is required') - if (!tier) throw new Error('tier is required') - - const payload: { tier: string; payment_method_id?: string } = { - tier, - payment_method_id: paymentMethodId, - } - - const response = await post( - `${API_URL}/organizations/${organizationSlug}/org-billing-migration`, - payload - ) - if (response.error) throw response.error - - return response -} - -type OrganizationBillingMigrationData = Awaited> - -export const useOrganizationBillingMigrationMutation = ({ - onSuccess, - onError, - ...options -}: Omit< - UseMutationOptions< - OrganizationBillingMigrationData, - ResponseError, - OrganizationBillingMigrationVariables - >, - 'mutationFn' -> = {}) => { - const queryClient = useQueryClient() - - return useMutation< - OrganizationBillingMigrationData, - ResponseError, - OrganizationBillingMigrationVariables - >((vars) => migrateBilling(vars), { - async onSuccess(data, variables, context) { - const { organizationSlug } = variables - await Promise.all([ - queryClient.invalidateQueries(organizationKeys.members(organizationSlug)), - queryClient.invalidateQueries(organizationKeys.list()), - queryClient.invalidateQueries(organizationKeys.freeProjectLimitCheck(organizationSlug)), - ]) - await onSuccess?.(data, variables, context) - }, - async onError(data, variables, context) { - if (onError === undefined) { - toast.error(`Failed to migrate billing: ${data.message}`) - } else { - onError(data, variables, context) - } - }, - ...options, - }) -} diff --git a/apps/studio/data/organizations/organization-migrate-billing-preview-query.ts b/apps/studio/data/organizations/organization-migrate-billing-preview-query.ts deleted file mode 100644 index 4b6628acecd..00000000000 --- a/apps/studio/data/organizations/organization-migrate-billing-preview-query.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query' -import { post } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' -import { organizationKeys } from './keys' -import { SubscriptionTier } from 'data/subscriptions/types' - -export type OrganizationBillingMigrationPreviewVariables = { - organizationSlug?: string - tier?: string -} - -export type OrganizationBillingMigrationPreviewResponse = { - added_credits: number - addons_to_be_removed: { - projectRef: string - projectName: string - addons: { variant: string; name: string; type: string }[] - }[] - monthly_invoice_breakdown: { - description: string - unit_price: number - quantity: number - total_price: number - }[] - old_tiers: SubscriptionTier[] -} - -export async function previewOrganizationBillingMigration( - { organizationSlug, tier }: OrganizationBillingMigrationPreviewVariables, - signal?: AbortSignal -) { - if (!organizationSlug) throw new Error('organizationSlug is required') - if (!tier) throw new Error('tier is required') - - const payload: { tier: string } = { - tier, - } - - const response = await post( - `${API_URL}/organizations/${organizationSlug}/org-billing-migration/preview`, - payload, - { signal } - ) - - if (response.error) throw response.error - - return response as OrganizationBillingMigrationPreviewResponse -} - -export type OrganizationBillingMigrationPreviewData = Awaited< - ReturnType -> -export type OrganizationBillingMigrationPreviewError = { - message: string -} - -export const useOrganizationBillingMigrationPreview = < - TData = OrganizationBillingMigrationPreviewData ->( - { organizationSlug, tier }: OrganizationBillingMigrationPreviewVariables, - { - enabled = true, - ...options - }: UseQueryOptions< - OrganizationBillingMigrationPreviewData, - OrganizationBillingMigrationPreviewError, - TData - > = {} -) => - useQuery< - OrganizationBillingMigrationPreviewData, - OrganizationBillingMigrationPreviewError, - TData - >( - organizationKeys.migrateBillingPreview(organizationSlug), - ({ signal }) => previewOrganizationBillingMigration({ organizationSlug, tier }, signal), - { - enabled: enabled && typeof organizationSlug !== 'undefined' && typeof tier !== 'undefined', - ...options, - - retry: (failureCount, error) => { - // Don't retry on 400s - if ( - typeof error === 'object' && - error !== null && - 'code' in error && - (error as any).code === 400 - ) { - return false - } - - if (failureCount < 3) { - return true - } - - return false - }, - } - )