Merge branch 'master' of github.com:supabase/supabase

This commit is contained in:
Terry Sutton committed 2022-10-14 09:20:55 -02:30
commit 2881b8952d
9 files changed
+954 -365

No files matched your search

@@ -76,9 +76,9 @@ async function getMovies() {
return await supabase.from('movies').select('id, title, actors(*)')
}
type actors = Database['public']['Tables']['actors']['Row']
type Actors = Database['public']['Tables']['actors']['Row']
type MoviesResponse = Awaited<ReturnType<typeof getMovies>>
type MoviesResponseSuccess = MoviesResponse['data'] & {
actors: actors[]
actors: Actors[]
}
```
+94 -83
View File
@@ -68,105 +68,116 @@ const EnterpriseContactForm = () => {
return (
<div>
<Form initialValues={INITIAL_VALUES} validate={validate} onSubmit={handleFormSubmit}>
{({ isSubmitting }: any) => (
<div className="flex flex-col space-y-4">
<div>
<Input
label="Company Name *"
id="companyName"
name="companyName"
layout="vertical"
placeholder="Supa Inc."
/>
</div>
{({ values, isSubmitting }: any) => {
const selectedCountry = countries.find((country) => country.code === values['country'])
const phonePlaceholder =
selectedCountry !== undefined ? `+${selectedCountry.phone_code}` : ''
<div className="flex space-x-4">
<div className="flex-1">
return (
<div className="flex flex-col space-y-4">
<div>
<Input
label="Your First Name *"
id="contactFirstName"
name="contactFirstName"
label="Company Name *"
id="companyName"
name="companyName"
layout="vertical"
placeholder="Jane"
placeholder="Supa Inc."
/>
</div>
<div className="flex-1">
<div className="flex space-x-4">
<div className="flex-1">
<Input
label="Your First Name *"
id="contactFirstName"
name="contactFirstName"
layout="vertical"
placeholder="Jane"
/>
</div>
<div className="flex-1">
<Input
label="Your Last Name *"
id="contactLastName"
name="contactLastName"
layout="vertical"
placeholder="Doe"
/>
</div>
</div>
<div>
<Input
label="Your Last Name *"
id="contactLastName"
name="contactLastName"
label="Your Business Email *"
id="contactEmail"
name="contactEmail"
layout="vertical"
placeholder="Doe"
placeholder="janedoe@example.com"
/>
</div>
</div>
<div>
<Input
label="Your Business Email *"
id="contactEmail"
name="contactEmail"
layout="vertical"
placeholder="janedoe@example.com"
/>
</div>
<div>
<Select label="Company Size" id="companySize" name="companySize" layout="vertical">
<Select.Option value="">{'--'}</Select.Option>
<Select.Option value="1-10">1-10 Employees</Select.Option>
<Select.Option value="11-50">11-50 Employees</Select.Option>
<Select.Option value="51-200">51-200 Employees</Select.Option>
<Select.Option value="201-500">201-500 Employees</Select.Option>
<Select.Option value="501-1000">501-1000 Employees</Select.Option>
<Select.Option value="1001-5000">1001-5000 Employees</Select.Option>
<Select.Option value="5001+">5001+ Employees</Select.Option>
</Select>
</div>
<div>
<Select label="Company Size" id="companySize" name="companySize" layout="vertical">
<Select.Option value="">{'--'}</Select.Option>
<Select.Option value="1-10">1-10 Employees</Select.Option>
<Select.Option value="11-50">11-50 Employees</Select.Option>
<Select.Option value="51-200">51-200 Employees</Select.Option>
<Select.Option value="201-500">201-500 Employees</Select.Option>
<Select.Option value="501-1000">501-1000 Employees</Select.Option>
<Select.Option value="1001-5000">1001-5000 Employees</Select.Option>
<Select.Option value="5001+">5001+ Employees</Select.Option>
</Select>
</div>
<div>
<Input
label="Your Phone Number"
id="contactPhone"
name="contactPhone"
layout="vertical"
placeholder={phonePlaceholder}
/>
</div>
<div>
<Input
label="Your Phone Number"
id="contactPhone"
name="contactPhone"
layout="vertical"
placeholder="+65 1234 1234"
/>
</div>
<div>
<Select
label="Country / Main Timezone"
id="country"
name="country"
layout="vertical"
>
{countries.map(({ code, name }) => (
<Select.Option key={code} value={code}>
{name}
</Select.Option>
))}
</Select>
</div>
<div>
<Select label="Country / Main Timezone" id="country" name="country" layout="vertical">
{countries.map(({ code, name }) => (
<Select.Option key={code} value={code}>
{name}
</Select.Option>
))}
</Select>
</div>
<div className="">
<Input.TextArea
id="details"
name="details"
label="Additional Details"
placeholder="Tell us about your projects, clients, and technology..."
rows={10}
/>
</div>
<div className="">
<Input.TextArea
id="details"
name="details"
label="Additional Details"
placeholder="Tell us about your projects, clients, and technology..."
rows={10}
/>
<div className="col-span-2 flex w-full flex-row-reverse pt-4">
<Button
size="xlarge"
disabled={isSubmitting}
loading={isSubmitting}
htmlType="submit"
>
Send
</Button>
</div>
</div>
<div className="col-span-2 flex w-full flex-row-reverse pt-4">
<Button
size="xlarge"
disabled={isSubmitting}
loading={isSubmitting}
htmlType="submit"
>
Send
</Button>
</div>
</div>
)}
)
}}
</Form>
{formSubmitted && (
+205
View File
@@ -0,0 +1,205 @@
import { Button, Form, Input, Select } from '@supabase/ui'
import { useState } from 'react'
import countries from '~/data/Countries.json'
import supabase from '~/lib/supabase'
const INITIAL_VALUES = {
companyName: '',
contactFirstName: '',
contactLastName: '',
contactEmail: '',
contactPhone: '',
companySize: '',
details: '',
country: 'US',
}
const validate = (values: any) => {
const errors: any = {}
if (!values.companyName) {
errors.companyName = 'Required'
}
if (!values.contactFirstName) {
errors.contactFirstName = 'Required'
}
if (!values.contactLastName) {
errors.contactLastName = 'Required'
}
if (!values.contactEmail) {
errors.contactEmail = 'Required'
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.contactEmail)) {
errors.contactEmail = 'Invalid email address'
}
return errors
}
const SOC2RequestForm = () => {
const [error, setError] = useState<string>()
const [formSubmitted, setFormSubmitted] = useState<boolean>(false)
const handleFormSubmit = async (values: typeof INITIAL_VALUES, { resetForm }: any) => {
const { error } = await supabase.from('soc2_requests').insert([
{
company_name: values.companyName,
contact_name: `${values.contactFirstName} ${values.contactLastName}`,
contact_first_name: values.contactFirstName,
contact_last_name: values.contactLastName,
contact_email: values.contactEmail,
contact_phone: values.contactPhone,
company_size: values.companySize,
details: values.details,
country: values.country,
},
])
if (!error) {
resetForm()
setFormSubmitted(true)
} else {
setError(error.message)
}
}
return (
<div>
{formSubmitted ? (
<h3 className="h3 text-brand-900 mt-12 text-center">
Thank you for your submission! A member from the Supabase team will reach out to you
shortly!
</h3>
) : (
<>
<Form initialValues={INITIAL_VALUES} validate={validate} onSubmit={handleFormSubmit}>
{({ values, isSubmitting }: any) => {
const selectedCountry = countries.find(
(country) => country.code === values['country']
)
const phonePlaceholder =
selectedCountry !== undefined ? `+${selectedCountry.phone_code}` : ''
return (
<div className="flex flex-col space-y-1">
<div>
<Input
label="Company Name *"
id="companyName"
name="companyName"
layout="vertical"
placeholder="Supa Inc."
/>
</div>
<div className="flex space-x-4">
<div className="flex-1">
<Input
label="Your First Name *"
id="contactFirstName"
name="contactFirstName"
layout="vertical"
placeholder="Jane"
/>
</div>
<div className="flex-1">
<Input
label="Your Last Name *"
id="contactLastName"
name="contactLastName"
layout="vertical"
placeholder="Doe"
/>
</div>
</div>
<div>
<Input
label="Your Business Email *"
id="contactEmail"
name="contactEmail"
layout="vertical"
placeholder="janedoe@example.com"
/>
</div>
<div>
<Select
label="Company Size"
id="companySize"
name="companySize"
layout="vertical"
>
<Select.Option value="">{'--'}</Select.Option>
<Select.Option value="1-10">1-10 Employees</Select.Option>
<Select.Option value="11-50">11-50 Employees</Select.Option>
<Select.Option value="51-200">51-200 Employees</Select.Option>
<Select.Option value="201-500">201-500 Employees</Select.Option>
<Select.Option value="501-1000">501-1000 Employees</Select.Option>
<Select.Option value="1001-5000">1001-5000 Employees</Select.Option>
<Select.Option value="5001+">5001+ Employees</Select.Option>
</Select>
</div>
<div>
<Select
label="Country / Main Timezone"
id="country"
name="country"
layout="vertical"
>
{countries.map(({ code, name }) => (
<Select.Option key={code} value={code}>
{name}
</Select.Option>
))}
</Select>
</div>
<div>
<Input
label="Your Phone Number"
id="contactPhone"
name="contactPhone"
layout="vertical"
placeholder={phonePlaceholder}
/>
</div>
<div className="">
<Input.TextArea
id="details"
name="details"
label="Additional Details"
placeholder="Tell us about your projects, clients, and technology..."
rows={10}
/>
</div>
<div className="col-span-2 flex w-full flex-row-reverse pt-4">
<Button
type="primary"
size="small"
className="text-white"
htmlType="submit"
disabled={isSubmitting}
loading={isSubmitting}
>
Submit request
</Button>
</div>
</div>
)
}}
</Form>
{error && <p className="text-sm">Error: {error}</p>}
</>
)}
</div>
)
}
export default SOC2RequestForm
File diff suppressed because it is too large. Load diff
+4
View File
@@ -62,6 +62,10 @@
{
"text": "DPA",
"url": "/legal/dpa"
},
{
"text": "SOC2",
"url": "/legal/soc2"
}
]
},
+78 -11
View File
@@ -1,10 +1,40 @@
import { Button } from '@supabase/ui'
import CTABanner from 'components/CTABanner/index'
import * as Yup from 'yup'
import Link from 'next/link'
import { useState } from 'react'
import { Button, Form, IconDownload, Input } from '@supabase/ui'
import supabase from '~/lib/supabase'
import CTABanner from 'components/CTABanner/index'
import Layout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
const DPA = () => {
const [email, setEmail] = useState<string>('')
const [error, setError] = useState<string>()
const [formSubmitted, setFormSubmitted] = useState<boolean>(false)
const INITIAL_VALUES = { email: '' }
const FormSchema = Yup.object().shape({
email: Yup.string().email('Invalid email').required('Required'),
})
const handleFormSubmit = async (values: typeof INITIAL_VALUES, { resetForm }: any) => {
try {
setError(undefined)
const { error } = await supabase
.from('dpa_downloads')
.insert([{ contact_email: values.email, document: 'dpa' }])
if (error) throw error
resetForm()
setFormSubmitted(true)
window.open('https://supabase.com/downloads/docs/Supabase+DPA+220503.pdf', '_blank')
} catch (error: any) {
setError(error.message)
}
}
return (
<>
<Layout>
@@ -19,14 +49,52 @@ const DPA = () => {
("DPA").
</p>
<p>You can download the latest DPA document through our security portal.</p>
<div>
<Link href="https://security.supabase.com">
<Button size="medium" type="default">
Security portal
</Button>
</Link>
</div>
<p>
You can download the latest DPA document through our{' '}
<Link href="https://security.supabase.com/">security portal</Link>, or by
submitting your email here.
</p>
{formSubmitted ? (
<p className="text-brand-900">
Thank you for your submission! A new tab should have opened with the DPA
document
</p>
) : (
<Form
initialValues={INITIAL_VALUES}
validationSchema={FormSchema}
onSubmit={handleFormSubmit}
>
{({ isSubmitting }: any) => (
<>
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
type="email"
name="email"
id="email"
required
descriptionText="We only keep a record of your email so we can update you when the document has been updated."
placeholder="Your email address"
error={error}
actions={
<Button
htmlType="submit"
type="default"
iconRight={<IconDownload />}
className="mr-1"
loading={isSubmitting}
>
Download DPA document
</Button>
}
/>
{error && <p>{error}</p>}
</>
)}
</Form>
)}
</div>
</div>
</div>
@@ -36,5 +104,4 @@ const DPA = () => {
</>
)
}
export default DPA
+36
View File
@@ -0,0 +1,36 @@
import Link from 'next/link'
import CTABanner from 'components/CTABanner/index'
import Layout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
import SOC2RequestForm from '~/components/SOC2RequestForm'
const SOC2 = () => {
return (
<Layout>
<SectionContainer>
<div className="mx-auto grid max-w-2xl grid-cols-12 rounded-lg">
<div className="col-span-12 flex items-center lg:col-span-12">
<div className="prose flex flex-col space-y-8 p-16">
<h1 className="text-center text-5xl">SOC2</h1>
<p>
As a database company, being SOC2 compliant is important when handling sensitive
customer data. Supabase is currently SOC2 Type 1 compliant and we're also working on
getting certified for SOC2 Type 2 and HIPAA next.
</p>
<p>
You can request for our latest SOC 2 document either through our{' '}
<Link href="https://security.supabase.com/">security portal</Link>, or by submitting
your request here.
</p>
<SOC2RequestForm />
</div>
</div>
</div>
</SectionContainer>
<CTABanner />
</Layout>
)
}
export default SOC2
@@ -4,6 +4,8 @@ const FUNCTION_SECRET = Deno.env.get('FUNCTION_SECRET')
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')
const DPA_FORM_ID = Deno.env.get('DPA_FORM_ID')
const SOC2_FORM_ID = Deno.env.get('SOC2_FORM_ID')
serve(async (req) => {
const requestSecret = req.headers.get('x-function-secret')
@@ -27,25 +29,32 @@ serve(async (req) => {
const website = input.record.website
const partner_gallery_type = input.record.type
let formData: object = {
supabase_table_id,
country,
form_note,
company,
company_size,
email,
phone,
lastName,
firstName,
}
let formData: object = { email }
if (input.table === 'partner_contacts') {
formData = {
...formData,
jobtitle,
website,
partner_gallery_type,
}
switch (input.table) {
case 'partner_contacts':
formData = { ...formData, jobtitle, website, partner_gallery_type }
break
case 'soc2_requests':
case 'enterprise_contacts':
formData = {
...formData,
supabase_table_id,
country,
form_note,
company,
company_size,
email,
phone,
lastName,
firstName,
}
break
case 'dpa_downloads':
formData = { ...formData }
break
default:
break
}
const fields: { objectTypeId: '0-1'; name: string; value: string }[] = []
@@ -53,7 +62,14 @@ serve(async (req) => {
fields.push({ objectTypeId: '0-1', name: key, value: value || 'NOT_PROVIDED' })
}
const formId = input.table === 'partner_contacts' ? PARTNER_FORM_ID : ENTERPRISE_FORM_ID
const formId =
input.table === 'partner_contacts'
? PARTNER_FORM_ID
: input.table === 'dpa_downloads'
? DPA_FORM_ID
: input.table === 'soc2_requests'
? SOC2_FORM_ID
: ENTERPRISE_FORM_ID
// Using HubSpot's submit data to a form API
// https://legacydocs.hubspot.com/docs/methods/forms/submit_form