Files
Danny White 64ba75d88b chore(studio): polish privacy policy notice (#43889)
## What kind of change does this PR introduce?

Minor polish

## What is the current behavior?

We have a privacy policy notice that uses `Alert_Shadcn_` with bespoke
links and badge.

## What is the new behavior?

- Reuse `Admonition` and `InlineLink` components
- Use sentence case as per our copywriting guidelines
- Tighten copywriting

| Before | After |
| --- | --- |
| <img width="1024" height="563" alt="Projects Boring Org Supabase"
src="https://github.com/user-attachments/assets/43fd9d4f-21e2-461b-92e3-d75578ae2ddd"
/> | <img width="1024" height="563" alt="Projects Boring Org
Supabase-27BBA2B8-4F90-4FB5-852D-B92B38AF5055"
src="https://github.com/user-attachments/assets/c0c09aae-c110-46cb-86ad-f6df557e1a4f"
/> |

## Additional context

Legal should sign off on this too.
2026-03-23 13:29:32 +08:00

134 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { zodResolver } from '@hookform/resolvers/zod'
import { useConsentState } from 'common'
import { LOCAL_STORAGE_KEYS } from 'common/constants/local-storage'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { InlineLink } from 'components/ui/InlineLink'
import { useSendResetMutation } from 'data/telemetry/send-reset-mutation'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { X } from 'lucide-react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { Card, CardContent, Form_Shadcn_, FormControl_Shadcn_, FormField_Shadcn_, Switch } from 'ui'
import { Admonition } from 'ui-patterns/admonition'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import {
PageSection,
PageSectionContent,
PageSectionDescription,
PageSectionMeta,
PageSectionSummary,
PageSectionTitle,
} from 'ui-patterns/PageSection'
import * as z from 'zod'
export const PrivacyUpdateBanner = () => {
const [privacyUpdateAcknowledged, setPrivacyUpdateAcknowledged] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.PRIVACY_NOTICE_ACKNOWLEDGED,
false
)
if (privacyUpdateAcknowledged) return null
return (
<Admonition
type="note"
title="Updates to our privacy policy"
description={
<>
We’ve clarified how we use analytics, cookies, and advertising tools in our{' '}
<InlineLink href="https://supabase.com/privacy">privacy policy</InlineLink>, effective
March 16, 2026. By continuing to use Supabase, you agree to the updated terms.{' '}
<InlineLink href="mailto:privacy@supabase.com">Contact us</InlineLink> with any
questions.{' '}
</>
}
className="mb-10 relative"
>
<ButtonTooltip
type="text"
icon={<X />}
className="absolute top-2 right-2 px-1"
onClick={() => setPrivacyUpdateAcknowledged(true)}
tooltip={{ content: { side: 'bottom', text: 'Dismiss' } }}
/>
</Admonition>
)
}
const AnalyticsSchema = z.object({
telemetryEnabled: z.boolean(),
})
export const AnalyticsSettings = () => {
const { hasAccepted, acceptAll, denyAll, categories } = useConsentState()
const hasLoaded = categories !== null
const { mutate: sendReset } = useSendResetMutation()
const form = useForm<z.infer<typeof AnalyticsSchema>>({
resolver: zodResolver(AnalyticsSchema),
values: { telemetryEnabled: hasAccepted },
})
const handleToggle = (value: boolean) => {
if (!hasLoaded) {
toast.error(
"We couldn't load the privacy settings due to an ad blocker or network error. Please disable any ad blockers and try again. If the problem persists, please contact support."
)
form.setValue('telemetryEnabled', !value)
return
}
if (value) {
acceptAll()
} else {
denyAll()
sendReset()
}
form.setValue('telemetryEnabled', value)
}
return (
<PageSection>
<PageSectionMeta>
<PageSectionSummary>
<PageSectionTitle>Analytics and Marketing</PageSectionTitle>
<PageSectionDescription>
Control whether telemetry and marketing data is sent from Supabase services.
</PageSectionDescription>
</PageSectionSummary>
</PageSectionMeta>
<PageSectionContent>
<Form_Shadcn_ {...form}>
<Card>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="telemetryEnabled"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Send telemetry data from Supabase services"
description="By opting in to sharing telemetry data, Supabase can analyze usage patterns to enhance user experience and use it for marketing and advertising purposes"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={(value) => {
field.onChange(value)
handleToggle(value)
}}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</CardContent>
</Card>
</Form_Shadcn_>
</PageSectionContent>
</PageSection>
)
}