diff --git a/apps/temp-community-forum/src/pages/_app.tsx b/apps/temp-community-forum/src/pages/_app.tsx index 9e7c3835d77..2d0cd5807e9 100644 --- a/apps/temp-community-forum/src/pages/_app.tsx +++ b/apps/temp-community-forum/src/pages/_app.tsx @@ -1,6 +1,6 @@ import React from 'react' import Main from '.' -import '../styles/main.css' +import '../styles/tailwind.css' const Index = () => { return
diff --git a/apps/temp-community-tutorials/src/pages/_app.tsx b/apps/temp-community-tutorials/src/pages/_app.tsx index 9e7c3835d77..2d0cd5807e9 100644 --- a/apps/temp-community-tutorials/src/pages/_app.tsx +++ b/apps/temp-community-tutorials/src/pages/_app.tsx @@ -1,6 +1,6 @@ import React from 'react' import Main from '.' -import '../styles/main.css' +import '../styles/tailwind.css' const Index = () => { return
diff --git a/apps/temp-docs/docs/guides/with-angular.mdx b/apps/temp-docs/docs/guides/with-angular.mdx index c620b531eed..ad0aae38d2d 100644 --- a/apps/temp-docs/docs/guides/with-angular.mdx +++ b/apps/temp-docs/docs/guides/with-angular.mdx @@ -54,7 +54,7 @@ or you can just copy/paste the SQL from below and run it yourself. ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-flutter.mdx b/apps/temp-docs/docs/guides/with-flutter.mdx index cd4fdbb600e..f150b2d309f 100644 --- a/apps/temp-docs/docs/guides/with-flutter.mdx +++ b/apps/temp-docs/docs/guides/with-flutter.mdx @@ -47,7 +47,7 @@ defaultActiveId="UI" ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-nextjs.mdx b/apps/temp-docs/docs/guides/with-nextjs.mdx index 93b0559ffff..d1a2abe4676 100644 --- a/apps/temp-docs/docs/guides/with-nextjs.mdx +++ b/apps/temp-docs/docs/guides/with-nextjs.mdx @@ -65,7 +65,7 @@ or you can just copy/paste the SQL from below and run it yourself. ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-react.mdx b/apps/temp-docs/docs/guides/with-react.mdx index 457f67f6200..9f26002872f 100644 --- a/apps/temp-docs/docs/guides/with-react.mdx +++ b/apps/temp-docs/docs/guides/with-react.mdx @@ -62,7 +62,7 @@ or you can just copy/paste the SQL from below and run it yourself. ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-redwoodjs.mdx b/apps/temp-docs/docs/guides/with-redwoodjs.mdx index 2fd1d6015b4..377e0b2ff94 100644 --- a/apps/temp-docs/docs/guides/with-redwoodjs.mdx +++ b/apps/temp-docs/docs/guides/with-redwoodjs.mdx @@ -114,7 +114,7 @@ defaultActiveId="UI" ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 4. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-svelte.mdx b/apps/temp-docs/docs/guides/with-svelte.mdx index f954143629d..7608069d74e 100644 --- a/apps/temp-docs/docs/guides/with-svelte.mdx +++ b/apps/temp-docs/docs/guides/with-svelte.mdx @@ -50,7 +50,7 @@ defaultActiveId="UI" ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/guides/with-vue-3.mdx b/apps/temp-docs/docs/guides/with-vue-3.mdx index 47897d4e21e..9ee3584e92c 100644 --- a/apps/temp-docs/docs/guides/with-vue-3.mdx +++ b/apps/temp-docs/docs/guides/with-vue-3.mdx @@ -47,7 +47,7 @@ defaultActiveId="UI" ```sh -1. Go to the "SQL" section. +1. Go to the "SQL Editor" section. 2. Click "User Management Starter". 3. Click "Run". ``` diff --git a/apps/temp-docs/docs/javascript/auth-signin.mdx b/apps/temp-docs/docs/javascript/auth-signin.mdx index 7cfa7a403e8..40acefd8e88 100644 --- a/apps/temp-docs/docs/javascript/auth-signin.mdx +++ b/apps/temp-docs/docs/javascript/auth-signin.mdx @@ -194,7 +194,7 @@ const { user, session, error } = await supabase.auth.signIn({ ### Sign in with redirect. Sometimes you want to control where the user is redirected to after they are logged in. Supabase supports this for -any URL path on your website (the base domain must be the same as the domain in your Auth settings). +any URL path on your website (the URL must either be on the same domain as your Site URL [see Auth>Settings in dashboard], or must match one of the Additional Redirect URLs [also in Auth>Settings]). Settings in dashboard], or must match one of the Additional Redirect URLs [also in Auth>Settings]). { <>

- We've raised over $36 million in funding, backed by some of the world's leading + We've raised over $116 million in funding, backed by some of the world's leading investors.

@@ -256,7 +256,7 @@ const Investors = () => { /> -
+
{InvestorData.filter((x) => x.lead === true).map((x) => (
{
-
+
{PressData.filter((x) => x.type == 'article').map((x) => ( diff --git a/apps/www/supabase/functions/hubspot-notification/index.ts b/apps/www/supabase/functions/hubspot-notification/index.ts index aa1c18a981a..e26d917cfee 100644 --- a/apps/www/supabase/functions/hubspot-notification/index.ts +++ b/apps/www/supabase/functions/hubspot-notification/index.ts @@ -1,12 +1,9 @@ import { serve } from 'https://deno.land/std@0.131.0/http/server.ts' const FUNCTION_SECRET = Deno.env.get('FUNCTION_SECRET') -const HUBSPOT_API_KEY = Deno.env.get('HUBSPOT_API_KEY') -const OWNER_ID = Deno.env.get('OWNER_ID') -const ENTERPRISE_PIPELINE = Deno.env.get('ENTERPRISE_PIPELINE') -const PARTNERS_PIPELINE = Deno.env.get('PARTNERS_PIPELINE') -const ENTERPRISE_DEAL_STAGE = Deno.env.get('ENTERPRISE_DEAL_STAGE') -const PARTNERS_DEAL_STAGE = Deno.env.get('PARTNERS_DEAL_STAGE') +const HUBSPOT_PORTAL = Deno.env.get('HUBSPOT_PORTAL') +const PARTNER_FORM_ID = Deno.env.get('PARTNER_FORM_ID') +const ENTERPRISE_FORM_ID = Deno.env.get('ENTERPRISE_FORM_ID') serve(async (req) => { const requestSecret = req.headers.get('x-function-secret') @@ -17,14 +14,51 @@ serve(async (req) => { const input = await req.json() - const firstName = input.record.contact_first_name || input.record.first - const lastName = input.record.contact_last_name || input.record.last + const supabase_table_id = input.record.id + const country = input.record.country + const form_note = input.record.details const company = input.record.company_name || input.record.company + const company_size = input.record.company_size || input.record.size const email = input.record.contact_email || input.record.email const phone = input.record.contact_phone || input.record.phone + const lastName = input.record.contact_last_name || input.record.last + const firstName = input.record.contact_first_name || input.record.first + const jobtitle = input.record.title + const website = input.record.website + const partner_gallery_type = input.record.type - const contactResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/contacts?hapikey=${HUBSPOT_API_KEY}`, + let formData: object = { + supabase_table_id, + country, + form_note, + company, + company_size, + email, + phone, + lastName, + firstName, + } + + if (input.table === 'partner_contacts') { + formData = { + ...formData, + jobtitle, + website, + partner_gallery_type, + } + } + + const fields: { objectTypeId: '0-1'; name: string; value: string }[] = [] + for (const [key, value] of Object.entries(formData)) { + fields.push({ objectTypeId: '0-1', name: key, value: value }) + } + + const formId = input.table === 'partner_contacts' ? PARTNER_FORM_ID : ENTERPRISE_FORM_ID + + // Using HubSpot's submit data to a form API + // https://legacydocs.hubspot.com/docs/methods/forms/submit_form + const formResponse = await fetch( + `https://api.hsforms.com/submissions/v3/integration/submit/${HUBSPOT_PORTAL}/${formId}`, { method: 'POST', headers: { @@ -32,143 +66,18 @@ serve(async (req) => { 'Content-Type': 'application/json', }, body: JSON.stringify({ - properties: { - company, - email, - firstname: firstName, - lastname: lastName, - phone, - }, + fields, }), } ) - const body = await contactResponse.json() + // Will create a deal using HubSpot's workflow tool instead of via API - let contactId: string | null = null - - if (contactResponse.ok) { - contactId = body.id - } else { - if (body.status === 'error' && body.category === 'CONFLICT') { - // fetch existing contact - const contactAssociateResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/contacts/${email}?idProperty=email&hapikey=${HUBSPOT_API_KEY}` - ) - - const body = await contactAssociateResponse.json() - - if (contactAssociateResponse.ok) { - contactId = body.id - } else { - console.log(`Failed to fetch contact`, body) - return new Response(`Failed to fetch contact`, { status: 500 }) - } - } else { - console.log(`Failed to create contact`, body) - return new Response(`Failed to create contact`, { status: 500 }) - } - } - - const noteContent = Object.entries(input.record).reduce( - (acc, [key, value]) => acc + `${key}: ${value || 'NOT_PROVIDED'}
`, - '' - ) - - // Add note - const noteResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/notes?hapikey=${HUBSPOT_API_KEY}`, - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - properties: { - hs_timestamp: Date.now(), - hs_note_body: noteContent, - hubspot_owner_id: OWNER_ID, - }, - }), - } - ) - - const noteBody = await noteResponse.json() - - if (!noteResponse.ok) { - console.log(`Failed to add note`, noteBody) - return new Response(`Failed to add note`, { status: 500 }) - } - - const noteId = noteBody.id - - // Associate note with contact - const noteAssociateResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/notes/${noteId}/associations/contacts/${contactId}/note_to_contact?hapikey=${HUBSPOT_API_KEY}`, - { - method: 'PUT', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - } - ) - - if (!noteAssociateResponse.ok) { - console.log(`Failed to associate note`, await noteAssociateResponse.json()) - return new Response(`Failed to associate note`, { status: 500 }) - } - - // Create deal - const dealCloseDate = new Date() - dealCloseDate.setDate(dealCloseDate.getDate() + 28) // 28 days - - const dealResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/deals?hapikey=${HUBSPOT_API_KEY}`, - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - properties: { - closedate: dealCloseDate.toISOString(), - dealname: company || `${firstName} ${lastName}`, - dealstage: - input.table === 'enterprise_contacts' ? ENTERPRISE_DEAL_STAGE : PARTNERS_DEAL_STAGE, - hubspot_owner_id: OWNER_ID, - pipeline: input.table === 'enterprise_contacts' ? ENTERPRISE_PIPELINE : PARTNERS_PIPELINE, - }, - }), - } - ) - - const dealBody = await dealResponse.json() - - if (!dealResponse.ok) { - console.log(`Failed to create deal`, dealBody) - return new Response(`Failed to create deal: ` + dealBody.message, { status: 500 }) - } - - const dealId = dealBody.id - - // Associate contact with a deal - const dealAssociateResponse = await fetch( - `https://api.hubapi.com/crm/v3/objects/contacts/${contactId}/associations/deals/${dealId}/contact_to_deal?hapikey=${HUBSPOT_API_KEY}`, - { - method: 'PUT', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - } - ) - - if (!dealAssociateResponse.ok) { - console.log(`Failed to associate contact with deal`, await dealAssociateResponse.json()) - return new Response(`Failed to associate contact with deal`, { status: 500 }) + if (!formResponse.ok) { + console.log(`Failed to submit form data to HubSpot`, await formResponse.json()) + return new Response(`Failed to submit form data to HubSpot`, { + status: 500, + }) } return new Response(JSON.stringify({ done: true }), { diff --git a/examples/todo-list/react-native-todo-list/package-lock.json b/examples/todo-list/react-native-todo-list/package-lock.json index ba4239b3e4a..5a7c40a9f8f 100644 --- a/examples/todo-list/react-native-todo-list/package-lock.json +++ b/examples/todo-list/react-native-todo-list/package-lock.json @@ -4214,9 +4214,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -17284,9 +17284,9 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { "lodash": "^4.17.14" } diff --git a/examples/todo-list/react-native-ts-todo-list/package-lock.json b/examples/todo-list/react-native-ts-todo-list/package-lock.json index fa618f712d5..7bf08ee5081 100644 --- a/examples/todo-list/react-native-ts-todo-list/package-lock.json +++ b/examples/todo-list/react-native-ts-todo-list/package-lock.json @@ -4495,9 +4495,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -17949,9 +17949,9 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { "lodash": "^4.17.14" } diff --git a/studio/components/interfaces/App/AppBannerWrapper.tsx b/studio/components/interfaces/App/AppBannerWrapper.tsx new file mode 100644 index 00000000000..51117e187bd --- /dev/null +++ b/studio/components/interfaces/App/AppBannerWrapper.tsx @@ -0,0 +1,29 @@ +import { FC } from 'react' +import Link from 'next/link' +import { useFlag } from 'hooks' +import { IconExternalLink } from '@supabase/ui' + +const AppBannerWrapper: FC = ({ children }) => { + const ongoingIncident = useFlag('ongoingIncident') + + return ( +
+ ) +} + +export default AppBannerWrapper diff --git a/studio/components/interfaces/App/index.ts b/studio/components/interfaces/App/index.ts index f65fabe0209..4e92356a261 100644 --- a/studio/components/interfaces/App/index.ts +++ b/studio/components/interfaces/App/index.ts @@ -1,5 +1,6 @@ import PortalToast from './PortalToast' import GoTrueWrapper from './GoTrueWrapper/GoTrueWrapper' import RouteValidationWrapper from './RouteValidationWrapper' +import AppBannerWrapper from './AppBannerWrapper' -export { PortalToast, GoTrueWrapper, RouteValidationWrapper } +export { PortalToast, GoTrueWrapper, RouteValidationWrapper, AppBannerWrapper } diff --git a/studio/components/interfaces/Billing/AddOns/AddOns.utils.ts b/studio/components/interfaces/Billing/AddOns/AddOns.utils.ts index 8198cec09a0..fb55d21b3b3 100644 --- a/studio/components/interfaces/Billing/AddOns/AddOns.utils.ts +++ b/studio/components/interfaces/Billing/AddOns/AddOns.utils.ts @@ -7,7 +7,6 @@ export const formatComputeSizes = (computeSizes: any[]) => { const microOption = { id: '', name: 'Micro Add-on', - description: 'Basic set up to get started', metadata: { default_price_id: undefined, supabase_prod_id: 'addon_instance_micro', @@ -29,30 +28,23 @@ export const formatComputeSizes = (computeSizes: any[]) => { ], } + const addonsOrder = [ + 'addon_instance_small', + 'addon_instance_medium', + 'addon_instance_large', + 'addon_instance_xlarge', + 'addon_instance_xxlarge', + 'addon_instance_4xlarge', + 'addon_instance_8xlarge', + 'addon_instance_12xlarge', + 'addon_instance_16xlarge', + ] + return [microOption] .concat( - computeSizes.filter( - (option: any) => option.metadata.supabase_prod_id === 'addon_instance_small' - ) - ) - .concat( - computeSizes.filter( - (option: any) => option.metadata.supabase_prod_id === 'addon_instance_medium' - ) - ) - .concat( - computeSizes.filter( - (option: any) => option.metadata.supabase_prod_id === 'addon_instance_large' - ) - ) - .concat( - computeSizes.filter( - (option: any) => option.metadata.supabase_prod_id === 'addon_instance_xlarge' - ) - ) - .concat( - computeSizes.filter( - (option: any) => option.metadata.supabase_prod_id === 'addon_instance_xxlarge' - ) + addonsOrder.map((id: string) => { + return computeSizes.find((option: any) => option.metadata.supabase_prod_id === id) + }) ) + .filter((option) => option !== undefined) } diff --git a/studio/components/interfaces/Billing/AddOns/ComputeSizeSelection.tsx b/studio/components/interfaces/Billing/AddOns/ComputeSizeSelection.tsx index 48a32c0f2c4..dd7307bdda0 100644 --- a/studio/components/interfaces/Billing/AddOns/ComputeSizeSelection.tsx +++ b/studio/components/interfaces/Billing/AddOns/ComputeSizeSelection.tsx @@ -1,26 +1,21 @@ import { FC } from 'react' import Link from 'next/link' import { Badge, Button, Radio } from '@supabase/ui' -import { useStore } from 'hooks' + +import { useStore, useFlag } from 'hooks' import { getProductPrice } from '../Billing.utils' +import DisabledWarningDueToIncident from 'components/ui/DisabledWarningDueToIncident' interface Props { computeSizes: any[] - currentComputeSize: any selectedComputeSize: any onSelectOption: (option: any) => void } -const ComputeSizeSelection: FC = ({ - computeSizes, - currentComputeSize, - selectedComputeSize, - onSelectOption, -}) => { - // [Joshen] We should have some indication on what's the current compute - // size of the project based on currentComputeSize +const ComputeSizeSelection: FC = ({ computeSizes, selectedComputeSize, onSelectOption }) => { const { ui } = useStore() const projectRef = ui.selectedProjectRef + const addonUpdateDisabled = useFlag('disableProjectCreationAndUpdate') return (
@@ -29,49 +24,52 @@ const ComputeSizeSelection: FC = ({

Database add-ons

Optional
-

+

Choose the database instance size that best fits your needs

- - {computeSizes.map((option: any) => { - const defaultPrice = getProductPrice(option) - return ( -
- } - value={option.id} - optionalLabel={
${defaultPrice.unit_amount / 100} / month
} - checked={selectedComputeSize?.id === option.id} - onChange={() => onSelectOption(option)} - /> - ) - })} -
+ } + value={option.id} + optionalLabel={
${defaultPrice.unit_amount / 100} / month
} + checked={selectedComputeSize?.id === option.id} + onChange={() => onSelectOption(option)} + /> + ) + })} +
) } diff --git a/studio/components/interfaces/Billing/PaymentSummaryPanel/PaymentSummaryPanel.tsx b/studio/components/interfaces/Billing/PaymentSummaryPanel/PaymentSummaryPanel.tsx index d7a85a79601..58706c93761 100644 --- a/studio/components/interfaces/Billing/PaymentSummaryPanel/PaymentSummaryPanel.tsx +++ b/studio/components/interfaces/Billing/PaymentSummaryPanel/PaymentSummaryPanel.tsx @@ -10,7 +10,7 @@ import { Alert, } from '@supabase/ui' -import { useFlag, useStore } from 'hooks' +import { useStore } from 'hooks' import { STRIPE_PRODUCT_IDS } from 'lib/constants' import { SubscriptionPreview } from '../Billing.types' import { getProductPrice } from '../Billing.utils' @@ -57,14 +57,9 @@ const PaymentSummaryPanel: FC = ({ onConfirmPayment, isSubmitting, }) => { - /** - * Feature flags - */ - const nativeBilling = useFlag('nativeBilling') - const [showConfirmModal, setShowConfirmModal] = useState(false) - const { ui } = useStore() const projectRegion = ui.selectedProject?.region + const [showConfirmModal, setShowConfirmModal] = useState(false) const isChangingPlan = (currentPlan.prod_id !== STRIPE_PRODUCT_IDS.PAYG && currentPlan.prod_id !== selectedPlan?.id) || @@ -82,14 +77,14 @@ const PaymentSummaryPanel: FC = ({ return ( <>

Payment Summary

{/* Subscription details */}
-

Selected subscription

+

Selected subscription

{getPlanName(currentPlan)} @@ -109,57 +104,53 @@ const PaymentSummaryPanel: FC = ({

{/* Add on details */} - {nativeBilling && ( - <> - {projectRegion !== 'af-south-1' && ( -
-

Selected add-ons

- {currentComputeSize === undefined && selectedComputeSize === undefined && ( -

No add-ons selected

- )} - {currentComputeSize !== undefined && ( -
-

- {currentComputeSize.name} -

-

- ${(getProductPrice(currentComputeSize).unit_amount / 100).toFixed(2)} -

-
- )} - {isChangingComputeSize && ( -
-

{selectedComputeSize.name}

-

- ${(getProductPrice(selectedComputeSize).unit_amount / 100).toFixed(2)} -

-
- )} - {isChangingComputeSize && ( -
- } - title="Changing your compute size" - description="It will take up to 2 minutes for changes to take place, and your project will be unavailable during that time" - /> -
- )} + {projectRegion !== 'af-south-1' && ( +
+

Selected add-ons

+ {currentComputeSize === undefined && selectedComputeSize === undefined && ( +

No add-ons selected

+ )} + {currentComputeSize !== undefined && ( +
+

+ {currentComputeSize.name} +

+

+ ${(getProductPrice(currentComputeSize).unit_amount / 100).toFixed(2)} +

)} - + {isChangingComputeSize && ( +
+

{selectedComputeSize.name}

+

+ ${(getProductPrice(selectedComputeSize).unit_amount / 100).toFixed(2)} +

+
+ )} + {isChangingComputeSize && ( +
+ } + title="Changing your compute size" + description="It will take up to 2 minutes for changes to take place, and your project will be unavailable during that time" + /> +
+ )} +
)} -
+
= ({

Select payment method

{isLoadingPaymentMethods ? ( -
+
-

Retrieving payment methods

+

Retrieving payment methods

) : paymentMethods.length === 0 ? ( -
-
+
+

No saved payment methods

@@ -214,11 +205,11 @@ const PaymentSummaryPanel: FC = ({ ) })}
-

+

Add new payment method

@@ -247,7 +238,7 @@ const PaymentSummaryPanel: FC = ({ header="Updating project database instance size" onCancel={() => setShowConfirmModal(false)} > -
+
= ({ -

Would you like to update your project now?

+

Would you like to update your project now?

diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx index 268a2196f28..443b7ec98ff 100644 --- a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx @@ -1,8 +1,10 @@ import { FC } from 'react' import { Button, IconLoader } from '@supabase/ui' +import * as Tooltip from '@radix-ui/react-tooltip' +import { useFlag } from 'hooks' import { STRIPE_PRODUCT_IDS } from 'lib/constants' -import { StripeProduct } from '../..' +import { StripeProduct } from 'components/interfaces/Billing' import Link from 'next/link' interface Props { @@ -12,6 +14,8 @@ interface Props { } const PlanCTAButton: FC = ({ plan, currentPlan, onSelectPlan }) => { + const projectUpdateDisabled = useFlag('disableProjectCreationAndUpdate') + const getButtonType = (plan: any) => { if (plan.name === 'Enterprise' || plan.id === STRIPE_PRODUCT_IDS.FREE) { return 'default' @@ -71,9 +75,9 @@ const PlanCTAButton: FC = ({ plan, currentPlan, onSelectPlan }) => { } return ( -
+
+ {!disabled && projectUpdateDisabled && ( +

+ Subscription changes are currently disabled, our engineers are working on a fix +

+ )}
) } diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.tsx b/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.tsx index ec9151ccf62..8ddc8587913 100644 --- a/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.tsx +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.tsx @@ -1,7 +1,8 @@ -import { IconCheck } from '@supabase/ui' -import { STRIPE_PRODUCT_IDS } from 'lib/constants' import { FC } from 'react' -import { StripeProduct } from '../..' +import { IconCheck } from '@supabase/ui' + +import { STRIPE_PRODUCT_IDS } from 'lib/constants' +import { StripeProduct } from 'components/interfaces/Billing' import PlanCTAButton from './PlanCTAButton' import { PRICING_META } from './Plans.Constants' @@ -14,8 +15,8 @@ interface Props { const AnimatedGradientBackground = () => (
) @@ -23,10 +24,10 @@ const AnimatedGradientBackground = () => ( const CurrentSubscriptionBanner = () => (

Current plan

@@ -52,30 +53,30 @@ const Plans: FC = ({ plans, currentPlan, onSelectPlan }) => { return (
{plan.id === STRIPE_PRODUCT_IDS.PRO && ( -
+
)} -
+
{isCurrentPlan && } -
+
{PRICING_META[plan.id].name} -
+
{PRICING_META[plan.id].priceMonthly !== undefined ? ( <>
{PRICING_META[plan.id].from && ( - From + From )}
${PRICING_META[plan.id].priceMonthly} - /mo + /mo
@@ -84,7 +85,7 @@ const Plans: FC = ({ plans, currentPlan, onSelectPlan }) => { )}
{PRICING_META[plan.id].warning && ( -
+
{PRICING_META[plan.id].warning}
)} @@ -98,28 +99,28 @@ const Plans: FC = ({ plans, currentPlan, onSelectPlan }) => { onSelectPlan={onSelectPlan} />
-

{PRICING_META[plan.id].description}

+

{PRICING_META[plan.id].description}