Skip to content

Commit 838fe7f

Browse files
authored
chore: migrate Organization settings Modal to Dialog (supabase#46332)
## Problem Organization settings still uses the deprecated `Modal` for: - downgrading subscription - requesting feedback after downgrading - showing an alert about members limit - requesting feedback after upgrading - deleting a published OAuth app - showing preview of a new OAuth app - Revoking an OAuth app ## Solution - use `Dialog` instead <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Replaced legacy modal UI with the app's modern dialog/alert-dialog components across billing and OAuth settings (upgrade/downgrade, exit survey, members-limit, delete/revoke, preview), keeping existing content and flows. * Confirm/cancel flows updated for more reliable async handling and clearer loading/disabled states during actions. <!-- 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/46332?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 71775c3 commit 838fe7f

7 files changed

Lines changed: 380 additions & 304 deletions

File tree

apps/studio/components/interfaces/Organization/BillingSettings/Subscription/DowngradeModal.tsx

Lines changed: 90 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import { MinusCircle, PauseCircle } from 'lucide-react'
22
import { useMemo } from 'react'
33
import { plans as subscriptionsPlans } from 'shared-data/plans'
4-
import { Modal } from 'ui'
4+
import {
5+
AlertDialog,
6+
AlertDialogAction,
7+
AlertDialogCancel,
8+
AlertDialogContent,
9+
AlertDialogDescription,
10+
AlertDialogFooter,
11+
AlertDialogHeader,
12+
AlertDialogTitle,
13+
} from 'ui'
514
import { Admonition } from 'ui-patterns'
615

716
import { getComputeSize, OrgProject } from '@/data/projects/org-projects-infinite-query'
@@ -78,83 +87,92 @@ const DowngradeModal = ({
7887
})
7988

8089
return (
81-
<Modal
82-
size="large"
83-
alignFooter="right"
84-
variant="warning"
85-
visible={visible}
86-
onCancel={onClose}
87-
onConfirm={onConfirm}
88-
header={`Confirm to downgrade to ${selectedPlan?.name} plan`}
89-
>
90-
<Modal.Content>
91-
<div className="space-y-2">
92-
<Admonition
93-
type="warning"
94-
title="Downgrading to the Free Plan will lead to reductions in your organization's quota"
95-
description="If you're already past the limits of the Free Plan, your projects could become
96-
unresponsive or enter read only mode."
97-
/>
98-
99-
{((previousProjectAddons.length ?? 0) > 0 || hasInstancesOnMicro) && (
100-
<Admonition type="warning" title="Projects affected by the downgrade">
101-
<ul className="space-y-1 max-h-[100px] overflow-y-auto">
102-
{previousProjectAddons.map((project) => (
103-
<ProjectDowngradeListItem key={project.ref} projectAddon={project} />
104-
))}
105-
106-
{projects
107-
.filter((it) => {
108-
const computeSize = getComputeSize(it)
109-
return computeSize === 'micro'
110-
})
111-
.map((project) => (
112-
<li className="list-disc ml-6" key={project.ref}>
113-
{project.name}: Compute will be downgraded. Project will also{' '}
114-
<span className="font-bold">need to be restarted</span>.
115-
</li>
116-
))}
117-
</ul>
118-
</Admonition>
119-
)}
120-
</div>
121-
122-
<ul className="mt-4 space-y-5 text-sm">
123-
<li className="flex items-center gap-3">
124-
<PauseCircle size={18} />
125-
<span>Projects will be paused after a week of inactivity</span>
126-
</li>
127-
128-
<li className="flex items-center gap-3 mb-2">
129-
<MinusCircle size={18} />
130-
<span>Add ons from all projects under this organization will be removed.</span>
131-
</li>
132-
133-
<li className="flex gap-3">
90+
<AlertDialog open={visible} onOpenChange={onClose}>
91+
<AlertDialogContent size="large">
92+
<AlertDialogHeader>
93+
<AlertDialogTitle>{`Confirm to downgrade to ${selectedPlan?.name} plan`}</AlertDialogTitle>
94+
<AlertDialogDescription asChild>
13495
<div>
135-
<strong>Before you downgrade to the {selectedPlan?.name} plan, consider:</strong>
136-
<ul className="space-y-2 mt-2">
137-
<li className="list-disc ml-6 text-foreground-light">
138-
Your projects no longer require their respective add-ons.
96+
<div className="flex flex-col space-y-2">
97+
<Admonition
98+
type="warning"
99+
title="Downgrading to the Free Plan will lead to reductions in your organization's quota"
100+
description="If you're already past the limits of the Free Plan, your projects could become
101+
unresponsive or enter read only mode."
102+
/>
103+
104+
{((previousProjectAddons.length ?? 0) > 0 || hasInstancesOnMicro) && (
105+
<Admonition type="warning" title="Projects affected by the downgrade">
106+
<ul className="space-y-1 max-h-[100px] overflow-y-auto">
107+
{previousProjectAddons.map((project) => (
108+
<ProjectDowngradeListItem key={project.ref} projectAddon={project} />
109+
))}
110+
111+
{projects
112+
.filter((it) => {
113+
const computeSize = getComputeSize(it)
114+
return computeSize === 'micro'
115+
})
116+
.map((project) => (
117+
<li className="list-disc ml-6" key={project.ref}>
118+
{project.name}: Compute will be downgraded. Project will also{' '}
119+
<span className="font-bold">need to be restarted</span>.
120+
</li>
121+
))}
122+
</ul>
123+
</Admonition>
124+
)}
125+
</div>
126+
127+
<ul className="mt-4 space-y-5 text-sm">
128+
<li className="flex items-center gap-3">
129+
<PauseCircle size={18} />
130+
<span>Projects will be paused after a week of inactivity</span>
139131
</li>
140-
<li className="list-disc ml-6 text-foreground-light">
141-
Your resource consumption are well within the {selectedPlan?.name} plan's quota.
132+
133+
<li className="flex items-center gap-3 mb-2">
134+
<MinusCircle size={18} />
135+
<span>Add ons from all projects under this organization will be removed.</span>
142136
</li>
143-
<li className="list-disc ml-6 text-foreground-light">
144-
Alternatively, you may also transfer projects across organizations.
137+
138+
<li className="flex gap-3">
139+
<div>
140+
<strong>
141+
Before you downgrade to the {selectedPlan?.name} plan, consider:
142+
</strong>
143+
<ul className="space-y-2 mt-2">
144+
<li className="list-disc ml-6 text-foreground-light">
145+
Your projects no longer require their respective add-ons.
146+
</li>
147+
<li className="list-disc ml-6 text-foreground-light">
148+
Your resource consumption are well within the {selectedPlan?.name} plan's
149+
quota.
150+
</li>
151+
<li className="list-disc ml-6 text-foreground-light">
152+
Alternatively, you may also transfer projects across organizations.
153+
</li>
154+
</ul>
155+
</div>
145156
</li>
146157
</ul>
158+
159+
{subscription?.billing_via_partner === true &&
160+
subscription.billing_partner === 'fly' && (
161+
<p className="mt-4 text-sm">
162+
Your organization will be downgraded at the end of your current billing cycle.
163+
</p>
164+
)}
147165
</div>
148-
</li>
149-
</ul>
150-
151-
{subscription?.billing_via_partner === true && subscription.billing_partner === 'fly' && (
152-
<p className="mt-4 text-sm">
153-
Your organization will be downgraded at the end of your current billing cycle.
154-
</p>
155-
)}
156-
</Modal.Content>
157-
</Modal>
166+
</AlertDialogDescription>
167+
</AlertDialogHeader>
168+
<AlertDialogFooter>
169+
<AlertDialogCancel>Cancel</AlertDialogCancel>
170+
<AlertDialogAction variant="warning" onClick={onConfirm}>
171+
Confirm
172+
</AlertDialogAction>
173+
</AlertDialogFooter>
174+
</AlertDialogContent>
175+
</AlertDialog>
158176
)
159177
}
160178

apps/studio/components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx

Lines changed: 90 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import { useFlag, useParams } from 'common'
22
import { useState } from 'react'
33
import { toast } from 'sonner'
4-
import { Button, cn, Modal, TextArea } from 'ui'
4+
import {
5+
Button,
6+
cn,
7+
Dialog,
8+
DialogContent,
9+
DialogFooter,
10+
DialogHeader,
11+
DialogSection,
12+
DialogSectionSeparator,
13+
DialogTitle,
14+
TextArea,
15+
} from 'ui'
516
import { Admonition } from 'ui-patterns/admonition'
617

718
import { ProjectUpdateDisabledTooltip } from '../ProjectUpdateDisabledTooltip'
@@ -101,76 +112,84 @@ export const ExitSurveyModal = ({ visible, projects, onClose }: ExitSurveyModalP
101112
}
102113

103114
return (
104-
<Modal hideFooter size="xlarge" visible={visible} onCancel={onClose} header="Help us improve">
105-
<Modal.Content>
106-
<div className="space-y-4">
107-
<p className="text-sm text-foreground-light">
108-
What made you decide to downgrade your plan?
109-
</p>
110-
<div className="space-y-8 mt-6">
111-
<div className="flex flex-wrap gap-2" data-toggle="buttons">
112-
{shuffledReasons.map((option) => {
113-
const active = selectedReason[0] === option.value
114-
return (
115-
<label
116-
key={option.value}
117-
className={cn(
118-
'flex cursor-pointer items-center space-x-2 rounded-md py-1',
119-
'pl-2 pr-3 text-center text-sm',
120-
'shadow-xs transition-all duration-100',
121-
active
122-
? `bg-foreground text-background opacity-100 hover:bg-foreground/75`
123-
: `bg-border-strong text-foreground opacity-75 hover:opacity-100`
124-
)}
125-
>
126-
<input
127-
type="radio"
128-
name="options"
129-
value={option.value}
130-
className="hidden"
131-
checked={active}
132-
onChange={() => onSelectCancellationReason(option.value)}
133-
/>
134-
<div>{option.value}</div>
135-
</label>
136-
)
137-
})}
115+
<Dialog open={visible} onOpenChange={onClose}>
116+
<DialogContent size="xlarge">
117+
<DialogHeader>
118+
<DialogTitle>Help us improve</DialogTitle>
119+
</DialogHeader>
120+
<DialogSectionSeparator />
121+
<DialogSection>
122+
<div className="flex flex-col space-y-4">
123+
<p className="text-sm text-foreground-light">
124+
What made you decide to downgrade your plan?
125+
</p>
126+
<div className="space-y-8 mt-6">
127+
<div className="flex flex-wrap gap-2" data-toggle="buttons">
128+
{shuffledReasons.map((option) => {
129+
const active = selectedReason[0] === option.value
130+
return (
131+
<label
132+
key={option.value}
133+
className={cn(
134+
'flex cursor-pointer items-center space-x-2 rounded-md py-1',
135+
'pl-2 pr-3 text-center text-sm',
136+
'shadow-xs transition-all duration-100',
137+
active
138+
? `bg-foreground text-background opacity-100 hover:bg-foreground/75`
139+
: `bg-border-strong text-foreground opacity-75 hover:opacity-100`
140+
)}
141+
>
142+
<input
143+
type="radio"
144+
name="options"
145+
value={option.value}
146+
className="hidden"
147+
checked={active}
148+
onChange={() => onSelectCancellationReason(option.value)}
149+
/>
150+
<div>{option.value}</div>
151+
</label>
152+
)
153+
})}
154+
</div>
155+
<div className="text-area-text-sm flex flex-col gap-y-2">
156+
<label htmlFor="message" className="text-sm whitespace-pre-line wrap-break-word">
157+
{textareaLabel}
158+
</label>
159+
<TextArea
160+
id="message"
161+
name="message"
162+
value={message}
163+
onChange={(event: any) => setMessage(event.target.value)}
164+
rows={3}
165+
/>
166+
</div>
138167
</div>
139-
<div className="text-area-text-sm flex flex-col gap-y-2">
140-
<label htmlFor="message" className="text-sm whitespace-pre-line wrap-break-word">
141-
{textareaLabel}
142-
</label>
143-
<TextArea
144-
id="message"
145-
name="message"
146-
value={message}
147-
onChange={(event: any) => setMessage(event.target.value)}
148-
rows={3}
168+
{hasProjectsWithComputeDowngrade && (
169+
<Admonition
170+
type="warning"
171+
layout="horizontal"
172+
title={`${projectsWithComputeDowngrade.length} of your projects will be restarted upon clicking confirm,`}
173+
description={
174+
<>
175+
This is due to changes in compute instances from the downgrade. Affected
176+
projects include{' '}
177+
{projectsWithComputeDowngrade.map((project) => project.name).join(', ')}.
178+
</>
179+
}
149180
/>
150-
</div>
181+
)}
182+
</div>
183+
184+
<div className="flex items-center justify-between border-t px-4 py-4">
185+
<p className="text-xs text-foreground-lighter">
186+
The unused amount for the remaining time of your billing cycle will be refunded as
187+
credits
188+
</p>
151189
</div>
152-
{hasProjectsWithComputeDowngrade && (
153-
<Admonition
154-
type="warning"
155-
layout="horizontal"
156-
title={`${projectsWithComputeDowngrade.length} of your projects will be restarted upon clicking confirm,`}
157-
description={
158-
<>
159-
This is due to changes in compute instances from the downgrade. Affected projects
160-
include {projectsWithComputeDowngrade.map((project) => project.name).join(', ')}.
161-
</>
162-
}
163-
/>
164-
)}
165-
</div>
166-
</Modal.Content>
167-
168-
<div className="flex items-center justify-between border-t px-4 py-4">
169-
<p className="text-xs text-foreground-lighter">
170-
The unused amount for the remaining time of your billing cycle will be refunded as credits
171-
</p>
172-
173-
<div className="flex items-center space-x-2">
190+
</DialogSection>
191+
192+
<DialogFooter>
174193
<Button type="default" onClick={() => onClose()}>
175194
Cancel
176195
</Button>
@@ -185,8 +204,8 @@ export const ExitSurveyModal = ({ visible, projects, onClose }: ExitSurveyModalP
185204
Confirm downgrade
186205
</Button>
187206
</ProjectUpdateDisabledTooltip>
188-
</div>
189-
</div>
190-
</Modal>
207+
</DialogFooter>
208+
</DialogContent>
209+
</Dialog>
191210
)
192211
}

0 commit comments

Comments
 (0)