Skip to content

Commit 51ecfbb

Browse files
authored
studio(chore): reuse org details fields in AWS marketplace flow (supabase#46087)
## What kind of change does this PR introduce? Refactor. Resolves FE-3216. ## What is the current behavior? The AWS Marketplace create-organisation dialog owns its own copy of the organisation name, type, and company-size form fields. It’s duplicative and has drifted from the normal `/new` organisation form, making the AWS flow harder to keep aligned. This is stacked on supabase#46058. ## What is the new behavior? - Extracts the shared organisation details schema, defaults, option constants, and fields from the normal `NewOrgForm` - Reuses those shared fields in both the full organisation creation form and the AWS Marketplace create-and-link dialog - Keeps the AWS Marketplace flow anchored in the onboarding interstitial rather than routing through `/new` - Keeps the AWS-specific buyer ID, AWS-managed organisation endpoint, create-and-link success state, and modal dismissal behaviour | Before | After | | --- | --- | | <img width="1024" height="759" alt="Link AWS Marketplace Supabase-3742FEDF-53BD-4E80-926D-498B2EA94773" src="https://github.com/user-attachments/assets/617ee422-1cf0-4858-801b-a4ee5ee402c9" /> | <img width="1024" height="759" alt="Link AWS Marketplace Supabase-0FEE2292-CB9F-43AA-B131-B6A549890970" src="https://github.com/user-attachments/assets/ff017468-f8ac-469a-bb17-eea07842306f" /> | ## Additional context The shared field extraction is intentionally limited to organisation details. Billing, plan selection, spend cap, Stripe, captcha, and the `/new/[slug]` redirect behaviour stay owned by `NewOrgForm`; AWS Marketplace keeps its separate create-and-link container because AWS owns the billing contract. ## Validation - `pnpm --filter studio exec vitest --run tests/pages/aws-marketplace-onboarding.test.tsx` - `pnpm --filter studio lint:ratchet --rule no-restricted-exports` - `git diff --check` Full Studio typecheck was also run, but it currently fails on existing unrelated repo-wide React/implicit-any errors outside this diff. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved AWS Marketplace organization creation dialog to prevent accidental closure while the creation process is in progress. * **Improvements** * Standardized organization details form handling across different organization creation flows for improved consistency and user experience. * **Tests** * Added comprehensive test coverage for the AWS Marketplace organization creation workflow, including form submission, validation, and state transitions. <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46087?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent a8720de commit 51ecfbb

6 files changed

Lines changed: 291 additions & 268 deletions

File tree

apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
useCloudMarketplaceOnboardingInfoQuery,
1919
type CloudMarketplaceOnboardingInfo,
2020
} from '@/components/interfaces/Organization/CloudMarketplace/cloud-marketplace-query'
21-
import NewAwsMarketplaceOrgModal from '@/components/interfaces/Organization/CloudMarketplace/NewAwsMarketplaceOrgModal'
21+
import { NewAwsMarketplaceOrgModal } from '@/components/interfaces/Organization/CloudMarketplace/NewAwsMarketplaceOrgModal'
2222
import { InterstitialAccountRow } from '@/components/layouts/InterstitialLayout'
2323
import { InlineLink } from '@/components/ui/InlineLink'
2424
import { useOrganizationLinkAwsMarketplaceMutation } from '@/data/organizations/organization-link-aws-marketplace-mutation'
Lines changed: 14 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,30 @@
11
import { zodResolver } from '@hookform/resolvers/zod'
22
import { useForm } from 'react-hook-form'
3-
import {
4-
Form,
5-
FormControl,
6-
FormField,
7-
Input,
8-
Label,
9-
Select,
10-
SelectContent,
11-
SelectItem,
12-
SelectTrigger,
13-
SelectValue,
14-
} from 'ui'
15-
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
16-
import { z } from 'zod'
17-
18-
const ORG_KIND_TYPES = {
19-
PERSONAL: 'Personal',
20-
EDUCATIONAL: 'Educational',
21-
STARTUP: 'Startup',
22-
AGENCY: 'Agency',
23-
COMPANY: 'Company',
24-
UNDISCLOSED: 'N/A',
25-
}
26-
27-
const ORG_KIND_DEFAULT = 'PERSONAL'
3+
import { Form } from 'ui'
284

29-
const ORG_SIZE_TYPES = {
30-
'1': '1 - 10',
31-
'10': '10 - 49',
32-
'50': '50 - 99',
33-
'100': '100 - 299',
34-
'300': 'More than 300',
35-
}
5+
import {
6+
ORG_KIND_DEFAULT,
7+
ORG_SIZE_DEFAULT,
8+
OrganizationDetailsFields,
9+
organizationDetailsSchema,
10+
type OrganizationDetailsFormValues,
11+
} from '../NewOrg/OrganizationDetailsFields'
3612

3713
interface Props {
3814
onSubmit: (values: NewMarketplaceOrgForm) => void
3915
}
4016

4117
export const CREATE_AWS_MANAGED_ORG_FORM_ID = 'create-aws-managed-org-form'
4218

43-
const FormSchema = z.object({
44-
name: z.string().trim().min(1, 'Please provide an organization name'),
45-
kind: z.string(),
46-
size: z.string().optional(),
47-
})
19+
export type NewMarketplaceOrgForm = OrganizationDetailsFormValues
4820

49-
export type NewMarketplaceOrgForm = z.infer<typeof FormSchema>
50-
51-
const NewAwsMarketplaceOrgForm = ({ onSubmit }: Props) => {
21+
export const NewAwsMarketplaceOrgForm = ({ onSubmit }: Props) => {
5222
const form = useForm<NewMarketplaceOrgForm>({
53-
resolver: zodResolver(FormSchema),
23+
resolver: zodResolver(organizationDetailsSchema),
5424
defaultValues: {
5525
name: '',
5626
kind: ORG_KIND_DEFAULT,
27+
size: ORG_SIZE_DEFAULT,
5728
},
5829
})
5930

@@ -62,98 +33,10 @@ const NewAwsMarketplaceOrgForm = ({ onSubmit }: Props) => {
6233
return (
6334
<Form {...form}>
6435
<form id={CREATE_AWS_MANAGED_ORG_FORM_ID} onSubmit={form.handleSubmit(onSubmit)}>
65-
<div className="flex flex-col gap-4">
66-
<FormField
67-
control={form.control}
68-
name="name"
69-
render={({ field }) => (
70-
<FormItemLayout label="Name" layout="horizontal">
71-
<FormControl>
72-
<>
73-
<Input {...field} placeholder="Organization name" />
74-
<div className="mt-1">
75-
<Label
76-
htmlFor="name"
77-
className="text-foreground-lighter leading-normal text-sm"
78-
>
79-
What's the name of your company or team?
80-
</Label>
81-
</div>
82-
</>
83-
</FormControl>
84-
</FormItemLayout>
85-
)}
86-
/>
87-
<FormField
88-
control={form.control}
89-
name="kind"
90-
render={({ field }) => (
91-
<FormItemLayout label="Type" layout="horizontal">
92-
<FormControl>
93-
<>
94-
<Select value={field.value} onValueChange={field.onChange}>
95-
<SelectTrigger>
96-
<SelectValue />
97-
</SelectTrigger>
98-
<SelectContent>
99-
{Object.entries(ORG_KIND_TYPES).map(([k, v]) => (
100-
<SelectItem key={k} value={k}>
101-
{v}
102-
</SelectItem>
103-
))}
104-
</SelectContent>
105-
</Select>
106-
<div className="mt-1">
107-
<Label
108-
htmlFor="kind"
109-
className="text-foreground-lighter leading-normal text-sm"
110-
>
111-
What would best describe your organization?
112-
</Label>
113-
</div>
114-
</>
115-
</FormControl>
116-
</FormItemLayout>
117-
)}
118-
/>
119-
{kind == 'COMPANY' && (
120-
<FormField
121-
control={form.control}
122-
name="size"
123-
render={({ field }) => (
124-
<FormItemLayout label="Company size" layout="horizontal">
125-
<FormControl>
126-
<>
127-
<Select value={field.value} onValueChange={field.onChange}>
128-
<SelectTrigger>
129-
<SelectValue placeholder="How many people are in your company?" />
130-
</SelectTrigger>
131-
<SelectContent>
132-
{Object.entries(ORG_SIZE_TYPES).map(([k, v]) => (
133-
<SelectItem key={k} value={k}>
134-
{v}
135-
</SelectItem>
136-
))}
137-
</SelectContent>
138-
</Select>
139-
<div className="mt-1">
140-
<Label
141-
htmlFor="size"
142-
className="text-foreground-lighter leading-normal text-sm"
143-
>
144-
How many people are in your company?
145-
</Label>
146-
</div>
147-
</>
148-
</FormControl>
149-
</FormItemLayout>
150-
)}
151-
/>
152-
)}
36+
<div className="flex flex-col gap-6">
37+
<OrganizationDetailsFields control={form.control} kind={kind} />
15338
</div>
15439
</form>
15540
</Form>
15641
)
15742
}
158-
159-
export default NewAwsMarketplaceOrgForm

apps/studio/components/interfaces/Organization/CloudMarketplace/NewAwsMarketplaceOrgModal.tsx

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import { SubmitHandler } from 'react-hook-form'
1212
import { toast } from 'sonner'
1313
import { Button } from 'ui'
1414

15-
import NewAwsMarketplaceOrgForm, {
15+
import {
1616
CREATE_AWS_MANAGED_ORG_FORM_ID,
17-
NewMarketplaceOrgForm,
17+
NewAwsMarketplaceOrgForm,
18+
type NewMarketplaceOrgForm,
1819
} from './NewAwsMarketplaceOrgForm'
1920
import { useAwsManagedOrganizationCreateMutation } from '@/data/organizations/organization-create-mutation'
2021

@@ -25,7 +26,7 @@ interface Props {
2526
onClose: () => void
2627
}
2728

28-
const NewAwsMarketplaceOrgModal = ({ buyerId, visible, onSuccess, onClose }: Props) => {
29+
export const NewAwsMarketplaceOrgModal = ({ buyerId, visible, onSuccess, onClose }: Props) => {
2930
const { mutate: createOrganization, isPending: isCreatingOrganization } =
3031
useAwsManagedOrganizationCreateMutation({
3132
onSuccess: (org) => {
@@ -40,39 +41,71 @@ const NewAwsMarketplaceOrgModal = ({ buyerId, visible, onSuccess, onClose }: Pro
4041
})
4142

4243
const onSubmit: SubmitHandler<NewMarketplaceOrgForm> = async (values) => {
43-
createOrganization({ ...values, buyerId })
44+
createOrganization({
45+
name: values.name,
46+
kind: values.kind,
47+
buyerId,
48+
...(values.kind === 'COMPANY' ? { size: values.size } : {}),
49+
})
50+
}
51+
52+
return (
53+
<AwsMarketplaceOrgCreationDialog
54+
visible={visible}
55+
onClose={onClose}
56+
onSubmit={onSubmit}
57+
isCreatingOrganization={isCreatingOrganization}
58+
/>
59+
)
60+
}
61+
62+
const AwsMarketplaceOrgCreationDialog = ({
63+
visible,
64+
onClose,
65+
onSubmit,
66+
isCreatingOrganization = false,
67+
}: {
68+
visible: boolean
69+
onClose: () => void
70+
onSubmit: SubmitHandler<NewMarketplaceOrgForm>
71+
isCreatingOrganization?: boolean
72+
}) => {
73+
const handleClose = () => {
74+
if (!isCreatingOrganization) onClose()
4475
}
4576

4677
return (
4778
<Dialog
4879
open={visible}
4980
onOpenChange={(open) => {
50-
if (!open) onClose()
81+
if (!open) handleClose()
5182
}}
5283
>
5384
<DialogContent
5485
onOpenAutoFocus={(event) => event.preventDefault()}
55-
size="xlarge"
56-
onEscapeKeyDown={(e) => (isCreatingOrganization ? e.preventDefault() : onClose())}
57-
onPointerDownOutside={(e) => (isCreatingOrganization ? e.preventDefault() : onClose())}
58-
className="p-2"
86+
size="medium"
87+
onEscapeKeyDown={(e) => {
88+
if (isCreatingOrganization) e.preventDefault()
89+
}}
90+
onPointerDownOutside={(e) => {
91+
if (isCreatingOrganization) e.preventDefault()
92+
}}
5993
>
6094
<DialogHeader>
61-
<DialogTitle>Create a new organization</DialogTitle>
62-
<DialogDescription>
95+
<DialogTitle>Create and link organization</DialogTitle>
96+
<DialogDescription className="text-balance">
6397
A new organization will be created and linked to your AWS Marketplace subscription
6498
</DialogDescription>
6599
</DialogHeader>
66100
<DialogSectionSeparator />
67101
<DialogSection>
68-
<NewAwsMarketplaceOrgForm onSubmit={onSubmit}></NewAwsMarketplaceOrgForm>
102+
<NewAwsMarketplaceOrgForm onSubmit={onSubmit} />
69103
</DialogSection>
70104
<DialogFooter>
71105
<Button
72106
form={CREATE_AWS_MANAGED_ORG_FORM_ID}
73107
htmlType="submit"
74108
loading={isCreatingOrganization}
75-
size="medium"
76109
>
77110
Create and link organization
78111
</Button>
@@ -81,5 +114,3 @@ const NewAwsMarketplaceOrgModal = ({ buyerId, visible, onSuccess, onClose }: Pro
81114
</Dialog>
82115
)
83116
}
84-
85-
export default NewAwsMarketplaceOrgModal

0 commit comments

Comments
 (0)