mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
## What kind of change does this PR introduce? Bug fix / design-system alignment for the legacy `Button` from `ui`. ## What is the current behavior? Omitting `variant` on the legacy `Button` falls back to brand-green `primary`. That makes accidental greens easy, and it is hard to spot the real main action on busy pages. ## What is the new behavior? - Legacy `Button` now defaults to neutral `default` - Intentional primary CTAs (create, save, submit, marketing CTAs, and matching `ButtonTooltip` usages) now set `variant="primary"` so their appearance is unchanged - Neutral actions that previously relied on the old fallback (cancel, close, back, dashboard nav, and similar) become grey/white - Design-system docs updated; regression tests cover the new default `Button_Shadcn_` is unchanged. It already uses its own CVA default. This is PR 1 of 2 in a stack. PR 2 drops now-redundant `variant="default"` props. ## To test Studio (http://localhost:8082): - `/sign-in`: Sign in stays green - Open a project → Database → Tables: New table stays green - Auth → Users → Invite: Invite user stays green; Cancel / dismiss controls stay neutral - Project Settings → General: edit a field so Cancel and Save appear. Cancel is neutral, Save is green Design system (http://localhost:3003): - Components → Button: default demo is neutral; primary demo is green; featured preview is the default variant Marketing (optional): - www header: Start your project stays green; logged-in Dashboard is neutral <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Style** - Buttons now default to a neutral style, while primary actions across Studio, documentation, marketing pages, forms, dialogs, and error states use prominent primary styling. - Updated button examples and previews clarify the distinction between default and primary variants. - Event registration now includes a directional arrow icon. - **Tests** - Added coverage confirming default button styling and explicit primary styling behave as expected. - Updated related test fixtures to use primary styling where appropriate. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
721 lines
23 KiB
TypeScript
721 lines
23 KiB
TypeScript
import { zodResolver } from '@hookform/resolvers/zod'
|
|
import {
|
|
SupaSquadApplication,
|
|
supaSquadApplicationSchema,
|
|
} from '~/data/open-source/contributing/supasquad.utils'
|
|
import { AlertCircle } from 'lucide-react'
|
|
import { FC, memo, useEffect, useState } from 'react'
|
|
import { useForm } from 'react-hook-form'
|
|
import {
|
|
Alert,
|
|
AlertDescription,
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
Button,
|
|
Form,
|
|
FormControl,
|
|
FormDescription,
|
|
FormField,
|
|
FormItem,
|
|
FormLabel,
|
|
FormMessage,
|
|
Input,
|
|
Separator,
|
|
TextArea,
|
|
} from 'ui'
|
|
import {
|
|
MultiSelector,
|
|
MultiSelectorContent,
|
|
MultiSelectorItem,
|
|
MultiSelectorList,
|
|
MultiSelectorTrigger,
|
|
} from 'ui-patterns/multi-select'
|
|
|
|
import { CountrySelector } from '../Supasquad/CountrySelector'
|
|
|
|
interface FormItem {
|
|
type: 'text' | 'textarea'
|
|
label: string
|
|
placeholder: string
|
|
required: boolean
|
|
className?: string
|
|
component: typeof TextArea | typeof Input
|
|
}
|
|
|
|
interface Track {
|
|
heading: string
|
|
description: string
|
|
}
|
|
|
|
interface Props {
|
|
className?: string
|
|
title?: string
|
|
description?: string
|
|
}
|
|
|
|
const tracks: Track[] = [
|
|
{
|
|
heading: 'Advocate',
|
|
description: 'Help spread word on socials answer community questions',
|
|
},
|
|
{
|
|
heading: 'Helper',
|
|
description: 'Answer questions and improve docs across our platforms',
|
|
},
|
|
{
|
|
heading: 'Builder/Maintainer',
|
|
description: 'Contribute to client libraries, manage issues, fix bugs',
|
|
},
|
|
{
|
|
heading: 'Moderator',
|
|
description: 'Ensure our social spaces remain productive and helpful',
|
|
},
|
|
]
|
|
|
|
const productAreasOfInterest: string[] = [
|
|
'Auth',
|
|
'AI Builders',
|
|
'Branching',
|
|
'Client libraries',
|
|
'Database / Postgres',
|
|
'Dashboard',
|
|
'CLI',
|
|
'Edge Functions',
|
|
'Integrations',
|
|
'Realtime',
|
|
'Storage',
|
|
'Vectors / AI',
|
|
'Other',
|
|
]
|
|
|
|
const languagesSpoken: string[] = [
|
|
'English',
|
|
'Spanish',
|
|
'Portuguese',
|
|
'French',
|
|
'German',
|
|
'Italian',
|
|
'Russian',
|
|
'Arabic',
|
|
'Hindi',
|
|
'Mandarin Chinese',
|
|
'Japanese',
|
|
'Turkish',
|
|
'Indonesian',
|
|
'Thai',
|
|
'Vietnamese',
|
|
'Bengali',
|
|
'Urdu',
|
|
'Polish',
|
|
'Dutch',
|
|
'Other',
|
|
]
|
|
|
|
const FormContent = memo(function FormContent({
|
|
form,
|
|
errors,
|
|
onSubmit,
|
|
honeypot,
|
|
setHoneypot,
|
|
isMobile,
|
|
isSubmitted,
|
|
handleCancel,
|
|
isSubmitting,
|
|
}: {
|
|
form: ReturnType<typeof useForm<SupaSquadApplication>>
|
|
errors: { [key: string]: string }
|
|
onSubmit: (data: SupaSquadApplication) => Promise<void>
|
|
honeypot: string
|
|
setHoneypot: React.Dispatch<React.SetStateAction<string>>
|
|
isMobile: boolean
|
|
isSubmitted: boolean
|
|
handleCancel: () => void
|
|
isSubmitting: boolean
|
|
}) {
|
|
return (
|
|
<div className="flex flex-col">
|
|
<Form {...form}>
|
|
<form
|
|
onSubmit={form.handleSubmit(onSubmit)}
|
|
className="space-y-6 text-left"
|
|
name="application-form"
|
|
noValidate
|
|
>
|
|
<div className="flex flex-col md:flex-row gap-4 items-start text-left">
|
|
<FormField
|
|
control={form.control}
|
|
name="first_name"
|
|
render={({ field }) => (
|
|
<FormItem className="w-full md:flex-1">
|
|
<FormLabel className="text-foreground">First Name *</FormLabel>
|
|
<FormControl>
|
|
<Input placeholder="Your first name" autoComplete="given-name" {...field} />
|
|
</FormControl>
|
|
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="last_name"
|
|
render={({ field }) => (
|
|
<FormItem className="w-full md:flex-1">
|
|
<FormLabel className="text-foreground">Last Name *</FormLabel>
|
|
<FormControl>
|
|
<div className="relative ">
|
|
<Input placeholder="Your last name" autoComplete="family-name" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="email"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Email Address *</FormLabel>
|
|
<FormControl>
|
|
<div className="relative">
|
|
<Input
|
|
type="email"
|
|
placeholder="Your personal or work email"
|
|
autoComplete="email"
|
|
{...field}
|
|
/>
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-8">
|
|
<h3 className="h3 text-foreground">Interests and skills</h3>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="tracks"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">
|
|
What track would you like to be considered for? *
|
|
</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
See longer descriptions of the 4 options above
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<MultiSelector
|
|
onValuesChange={(values) => {
|
|
// Convert selected headings back to track objects
|
|
const selectedTracks = values.map(
|
|
(heading) => tracks.find((track) => track.heading === heading)!
|
|
)
|
|
field.onChange(selectedTracks)
|
|
}}
|
|
values={field.value.map((track) => track.heading)}
|
|
size="small"
|
|
>
|
|
<MultiSelectorTrigger
|
|
mode="inline-combobox"
|
|
label="Select as many as you want"
|
|
badgeLimit="wrap"
|
|
showIcon={false}
|
|
deletableBadge
|
|
/>
|
|
<MultiSelectorContent>
|
|
<MultiSelectorList>
|
|
{tracks.map((item) => (
|
|
<MultiSelectorItem key={item.heading} value={item.heading}>
|
|
<div>
|
|
<div className="font-medium text-foreground">{item.heading}</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
{item.description}
|
|
</div>
|
|
</div>
|
|
</MultiSelectorItem>
|
|
))}
|
|
</MultiSelectorList>
|
|
</MultiSelectorContent>
|
|
</MultiSelector>
|
|
</div>
|
|
</FormControl>
|
|
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="why_you_want_to_join"
|
|
render={({ field }) => (
|
|
<FormItem className="space-y-1">
|
|
<FormLabel className="text-foreground">
|
|
Why do you want to join the program? *
|
|
</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
What do you have to contribute? What would you like to get out of it?
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative">
|
|
<TextArea
|
|
autoComplete="off"
|
|
rows={3}
|
|
className="bg-foreground/[.026]"
|
|
{...field}
|
|
/>
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="contributions"
|
|
render={({ field }) => (
|
|
<FormItem className="space-y-1">
|
|
<FormLabel className="text-foreground">
|
|
Share some of your recent contributions *
|
|
</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
<p>
|
|
Any relevant links to show your current engagement with the Supabase
|
|
community.
|
|
</p>
|
|
<p>
|
|
If you haven't contributed yet, spend some time engaging with the
|
|
community, then reapply once you've built up a few contributions.
|
|
</p>
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative">
|
|
<TextArea
|
|
autoComplete="off"
|
|
rows={3}
|
|
className="bg-foreground/[.026]"
|
|
placeholder="PR links, posts/replies on Discord/Reddit/X, Luma links of meetups
|
|
you have organized, etc."
|
|
{...field}
|
|
/>
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<Separator />
|
|
<FormField
|
|
control={form.control}
|
|
name="areas_of_interest"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Product Areas of Interest *</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
What specific areas would you like to help with? Leave blank if you're not
|
|
sure.
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<MultiSelector
|
|
onValuesChange={field.onChange}
|
|
values={field.value}
|
|
size="small"
|
|
>
|
|
<MultiSelectorTrigger
|
|
mode="inline-combobox"
|
|
label="Select as many as you want"
|
|
badgeLimit="wrap"
|
|
showIcon={false}
|
|
deletableBadge
|
|
/>
|
|
<MultiSelectorContent>
|
|
<MultiSelectorList>
|
|
{productAreasOfInterest.map((item) => (
|
|
<MultiSelectorItem key={item} value={item}>
|
|
{item}
|
|
</MultiSelectorItem>
|
|
))}
|
|
</MultiSelectorList>
|
|
</MultiSelectorContent>
|
|
</MultiSelector>
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="skills"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">
|
|
Skills (frameworks, tools, programming languages)
|
|
</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
Know Postgres really well? React? Expo? Python? Rust? Terraform? Add it here!
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input type="text" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-6">
|
|
<h3 className="h3 text-foreground">Location and Availability</h3>
|
|
|
|
<div className="flex flex-col md:flex-row gap-4 items-start text-left">
|
|
<FormField
|
|
control={form.control}
|
|
name="country"
|
|
render={({ field }) => (
|
|
<FormItem className="w-full md:flex-1">
|
|
<FormLabel className="text-foreground">Country *</FormLabel>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<CountrySelector value={field.value || ''} onValueChange={field.onChange} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="city"
|
|
render={({ field }) => (
|
|
<FormItem className="w-full md:flex-1">
|
|
<FormLabel className="text-foreground">City *</FormLabel>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input type="text" placeholder="City" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="monthly_commitment"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Monthly Commitment</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
How many hours can you commit per month? If not sure, leave blank.
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="languages_spoken"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Languages spoken *</FormLabel>
|
|
<FormDescription className="text-foreground-lighter">
|
|
What languages do you speak?
|
|
</FormDescription>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<MultiSelector
|
|
onValuesChange={field.onChange}
|
|
values={field.value}
|
|
size="small"
|
|
>
|
|
<MultiSelectorTrigger
|
|
mode="inline-combobox"
|
|
label="Select as many as you want"
|
|
badgeLimit="wrap"
|
|
showIcon={false}
|
|
deletableBadge
|
|
/>
|
|
<MultiSelectorContent>
|
|
<MultiSelectorList>
|
|
{languagesSpoken.map((item) => (
|
|
<MultiSelectorItem key={item} value={item}>
|
|
{item}
|
|
</MultiSelectorItem>
|
|
))}
|
|
</MultiSelectorList>
|
|
</MultiSelectorContent>
|
|
</MultiSelector>
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-6">
|
|
<h3 className="h4 text-foreground">Social Links</h3>
|
|
|
|
<div className="space-y-3">
|
|
<FormField
|
|
control={form.control}
|
|
name="discord"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Discord</FormLabel>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input type="text" placeholder="#username" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="github"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">GitHub</FormLabel>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input type="text" placeholder="@yourusername" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="twitter"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-foreground">Twitter</FormLabel>
|
|
<FormControl>
|
|
<div className="relative mt-1">
|
|
<Input type="text" placeholder="@yourhandle" {...field} />
|
|
</div>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{!isSubmitted && (
|
|
<div className="flex flex-row gap-3">
|
|
<Button
|
|
size="small"
|
|
type="button"
|
|
variant="outline"
|
|
onClick={handleCancel}
|
|
disabled={isSubmitting}
|
|
className="border-border text-foreground hover:bg-muted flex-1"
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
variant="primary"
|
|
size="small"
|
|
type="submit"
|
|
disabled={isSubmitting}
|
|
className="flex-1"
|
|
>
|
|
{isSubmitting ? <>Submitting...</> : <>Submit Application</>}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
|
|
{/* Spam prevention */}
|
|
<input
|
|
type="text"
|
|
name="honeypot"
|
|
value={honeypot}
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setHoneypot(e.target.value)}
|
|
className="hidden"
|
|
tabIndex={-1}
|
|
autoComplete="off"
|
|
aria-hidden="true"
|
|
/>
|
|
</form>
|
|
</Form>
|
|
|
|
{Object.values(errors).length > 0 && (
|
|
<Alert variant="destructive" className="mt-6">
|
|
<AlertCircle />
|
|
<AlertDescription>{Object.values(errors).join('\n')}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
)
|
|
})
|
|
|
|
const ApplyToSupaSquadForm: FC<Props> = ({
|
|
className,
|
|
title = 'Apply to join SupaSquad',
|
|
description = 'Join our community of passionate contributors and help shape the future of Supabase. Fill out the form below to apply.',
|
|
}) => {
|
|
const [honeypot, setHoneypot] = useState<string>('') // field to prevent spam
|
|
const [errors, setErrors] = useState<{ [key: string]: string }>({})
|
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
const [isSubmitted, setIsSubmitted] = useState(false)
|
|
const [success, setSuccess] = useState<string | null>(null)
|
|
const [showConfirmation, setShowConfirmation] = useState(false)
|
|
const [startTime, setStartTime] = useState<number>(0)
|
|
|
|
const form = useForm<SupaSquadApplication>({
|
|
resolver: zodResolver(supaSquadApplicationSchema),
|
|
defaultValues: {
|
|
first_name: '',
|
|
last_name: '',
|
|
email: '',
|
|
tracks: [],
|
|
areas_of_interest: [],
|
|
contributions: '',
|
|
skills: '',
|
|
why_you_want_to_join: '',
|
|
city: '',
|
|
country: '',
|
|
monthly_commitment: '',
|
|
languages_spoken: [],
|
|
github: '',
|
|
twitter: '',
|
|
discord: '',
|
|
},
|
|
mode: 'onBlur',
|
|
reValidateMode: 'onBlur',
|
|
})
|
|
|
|
const handleCancel = () => {
|
|
form.reset()
|
|
setIsSubmitted(false)
|
|
}
|
|
|
|
const handleConfirmationClose = () => {
|
|
form.reset()
|
|
setShowConfirmation(false)
|
|
setIsSubmitted(false)
|
|
setErrors({})
|
|
}
|
|
|
|
const onSubmit = async (data: SupaSquadApplication) => {
|
|
const currentTime = Date.now()
|
|
const timeElapsed = (currentTime - startTime) / 1000
|
|
|
|
// Spam prevention: Reject form if submitted too quickly (less than 3 seconds)
|
|
if (timeElapsed < 3) {
|
|
setErrors({ general: 'Submission too fast. Please fill the form correctly.' })
|
|
return
|
|
}
|
|
|
|
setIsSubmitting(true)
|
|
setSuccess(null)
|
|
|
|
try {
|
|
const response = await fetch('/api-v2/submit-form-apply-to-supasquad', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
})
|
|
|
|
if (response.ok) {
|
|
setSuccess('Thank you for your submission!')
|
|
setShowConfirmation(true)
|
|
} else {
|
|
const errorData = await response.json()
|
|
setErrors({ general: `Submission failed: ${errorData.message}` })
|
|
}
|
|
} catch (error) {
|
|
setErrors({ general: 'An unexpected error occurred. Please try again.' })
|
|
} finally {
|
|
setIsSubmitting(false)
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
setStartTime(Date.now())
|
|
}, [])
|
|
|
|
return (
|
|
<>
|
|
<div className={className}>
|
|
<div className="mb-6">
|
|
<h2 className="text-2xl font-semibold mb-2">{title}</h2>
|
|
<p className="text-muted-foreground">{description}</p>
|
|
</div>
|
|
|
|
<Separator className="my-6" />
|
|
|
|
<FormContent
|
|
form={form}
|
|
errors={errors}
|
|
onSubmit={onSubmit}
|
|
honeypot={honeypot}
|
|
setHoneypot={setHoneypot}
|
|
isMobile={false}
|
|
isSubmitted={isSubmitted}
|
|
handleCancel={handleCancel}
|
|
isSubmitting={isSubmitting}
|
|
/>
|
|
</div>
|
|
|
|
{/* Confirmation AlertDialog Overlay */}
|
|
<AlertDialog open={showConfirmation} onOpenChange={() => {}}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Application submitted</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
Thank you for your submission! Please check your email for a confirmation link to
|
|
complete your application.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogAction onClick={handleConfirmationClose}>Got it</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default ApplyToSupaSquadForm
|