mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Set up DPA and SOC2 pages
This commit is contained in:
1 parent
30a1bf0785
commit
bbecb30aa5
5 files changed
+219
-79
No files matched your search
@@ -0,0 +1,197 @@
|
||||
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}>
|
||||
{({ isSubmitting }: any) => (
|
||||
<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>
|
||||
<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 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
|
||||
@@ -20,7 +20,6 @@ const DPA = () => {
|
||||
})
|
||||
|
||||
const handleFormSubmit = async (values: typeof INITIAL_VALUES, { resetForm }: any) => {
|
||||
console.log('handleFormSubmit ran', values)
|
||||
try {
|
||||
setError(undefined)
|
||||
const { error } = await supabase
|
||||
@@ -31,7 +30,7 @@ const DPA = () => {
|
||||
|
||||
resetForm()
|
||||
setFormSubmitted(true)
|
||||
window.open('https://supabase.com/downloads/docs/legal/dpa.pdf', '_blank')
|
||||
window.open('https://supabase.com/downloads/docs/Supabase+DPA.pdf', '_blank')
|
||||
} catch (error: any) {
|
||||
setError(error.message)
|
||||
}
|
||||
@@ -58,7 +57,8 @@ const DPA = () => {
|
||||
|
||||
{formSubmitted ? (
|
||||
<p className="text-brand-900">
|
||||
A new tab should have opened with the DPA document
|
||||
Thank you for your submission! A new tab should have opened with the DPA
|
||||
document
|
||||
</p>
|
||||
) : (
|
||||
<Form
|
||||
@@ -83,6 +83,7 @@ const DPA = () => {
|
||||
htmlType="submit"
|
||||
type="default"
|
||||
iconRight={<IconDownload />}
|
||||
className="mr-1"
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Download DPA document
|
||||
|
||||
@@ -1,40 +1,10 @@
|
||||
import * as Yup from 'yup'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Button, Form, 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'
|
||||
import SOC2RequestForm from '~/components/SOC2RequestForm'
|
||||
|
||||
const SOC2 = () => {
|
||||
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) => {
|
||||
console.log('handleFormSubmit ran', values)
|
||||
try {
|
||||
setError(undefined)
|
||||
const { error } = await supabase
|
||||
.from('soc2_downloads')
|
||||
.insert([{ contact_email: values.email, document: 'soc2' }])
|
||||
|
||||
if (error) throw error
|
||||
|
||||
resetForm()
|
||||
setFormSubmitted(true)
|
||||
} catch (error: any) {
|
||||
setError(error.message)
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Layout>
|
||||
<SectionContainer>
|
||||
@@ -49,49 +19,12 @@ const SOC2 = () => {
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can request for our latest SOC 2 document through our{' '}
|
||||
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 email here.
|
||||
your request here.
|
||||
</p>
|
||||
|
||||
{formSubmitted ? (
|
||||
<p className="text-brand-900">
|
||||
Thank you for your submission! A member from the Supabase team will reach out to
|
||||
you shortly!
|
||||
</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"
|
||||
actions={
|
||||
<Button
|
||||
htmlType="submit"
|
||||
type="default"
|
||||
loading={isSubmitting}
|
||||
className="mr-1"
|
||||
>
|
||||
Request SOC2 document
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
{error && <p>{error}</p>}
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
)}
|
||||
<SOC2RequestForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
@@ -5,7 +5,7 @@ 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('DPA_FORM_ID')
|
||||
const SOC2_FORM_ID = Deno.env.get('SOC2_FORM_ID')
|
||||
|
||||
serve(async (req) => {
|
||||
const requestSecret = req.headers.get('x-function-secret')
|
||||
@@ -28,7 +28,6 @@ serve(async (req) => {
|
||||
const jobtitle = input.record.title
|
||||
const website = input.record.website
|
||||
const partner_gallery_type = input.record.type
|
||||
const document = input.document
|
||||
|
||||
let formData: object = { email }
|
||||
|
||||
@@ -36,6 +35,7 @@ serve(async (req) => {
|
||||
case 'partner_contacts':
|
||||
formData = { ...formData, jobtitle, website, partner_gallery_type }
|
||||
break
|
||||
case 'soc2_requests':
|
||||
case 'enterprise_contacts':
|
||||
formData = {
|
||||
...formData,
|
||||
@@ -50,9 +50,11 @@ serve(async (req) => {
|
||||
firstName,
|
||||
}
|
||||
break
|
||||
case 'soc2_downloads':
|
||||
case 'dpa_downloads':
|
||||
formData = { ...formData, document }
|
||||
formData = { ...formData }
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
const fields: { objectTypeId: '0-1'; name: string; value: string }[] = []
|
||||
@@ -60,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
|
||||
|
||||
Reference in new issue
Block a user