Delete auth user right away

This commit is contained in:
MartinBraquet
2025-10-29 16:22:11 +01:00
parent 07e2d2d509
commit 4ca3f3c8ee
4 changed files with 150 additions and 13 deletions

View File

@@ -4,18 +4,11 @@ import {createSupabaseDirectClient} from 'shared/supabase/init'
import * as admin from "firebase-admin";
import {deleteUserFiles} from "shared/firebase-utils";
export const deleteMe: APIHandler<'me/delete'> = async (body, auth) => {
const {username} = body
export const deleteMe: APIHandler<'me/delete'> = async (_, auth) => {
const user = await getUser(auth.uid)
if (!user) {
throw new APIError(401, 'Your account was not found')
}
if (user.username != username) {
throw new APIError(
400,
`Incorrect username. You are logged in as ${user.username}. Are you sure you want to delete this account?`
)
}
const userId = user.id
if (!userId) {
throw new APIError(400, 'Invalid user ID')

View File

@@ -238,9 +238,7 @@ export const API = (_apiTypeCheck = {
method: 'POST',
authed: true,
rateLimited: true,
props: z.object({
username: z.string(), // just so you're sure
}),
props: z.object({}),
summary: 'Delete the authenticated user account',
tag: 'Users',
},

View File

@@ -0,0 +1,146 @@
import {usePersistentInMemoryState} from "web/hooks/use-persistent-in-memory-state";
import {
notification_destination_types,
notification_preference,
notification_preferences
} from "common/user-notification-preferences";
import {useCallback} from "react";
import {debounce} from "lodash";
import {api} from "web/lib/api";
import {MultiSelectAnswers} from "web/components/answers/answer-compatibility-question-content";
import {usePrivateUser} from "web/hooks/use-user";
export const NotificationSettings = () => {
const privateUser = usePrivateUser()
if (!privateUser) return null
const [prefs, setPrefs] =
usePersistentInMemoryState<notification_preferences>(
privateUser.notificationPreferences,
'notification-preferences'
)
const notificationTypes: {
type: notification_preference
question: string
}[] = [
{
type: 'new_match',
question:
'... matches with you?',
},
{
type: 'new_message',
question: '... sends you a new message?',
},
// {
// type: 'new_profile_like',
// question: '... likes your profile?',
// },
{
type: 'new_endorsement',
question: '... endorses you?',
},
// {
// type: 'new_profile_ship',
// question: '... ships you?',
// },
{
type: 'tagged_user',
question: '... mentions you?',
},
// {
// type: 'on_new_follow',
// question: '... follows you?',
// },
{
type: 'new_search_alerts',
question: 'Alerts from bookmarked searches?',
},
{
type: 'opt_out_all',
question:
'Opt out of all notifications? (You can always change this later)',
},
]
return (
<div className="mx-auto max-w-2xl">
<div className="flex flex-col gap-8 p-4">
<p className="text-ink-700 font-medium">Where do you want to be notified when someone</p>
{notificationTypes.map(({type, question}) => (
<NotificationOption
key={type}
type={type}
question={question}
selected={prefs[type]}
onUpdate={(selected) => {
setPrefs((prevPrefs) => ({...prevPrefs, [type]: selected}))
}}
/>
))}
</div>
</div>
)
}
const NotificationOption = (props: {
type: notification_preference
question: string
selected: notification_destination_types[]
onUpdate: (selected: notification_destination_types[]) => void
}) => {
const {type, question, selected, onUpdate} = props
const getSelectedValues = (destinations: string[]) => {
const values: number[] = []
if ((destinations ?? []).includes('email')) values.push(0)
if ((destinations ?? []).includes('browser')) values.push(1)
return values
}
const setValue = async (value: number[]) => {
const newDestinations: notification_destination_types[] = []
if (value.includes(0)) newDestinations.push('email')
if (value.includes(1)) newDestinations.push('browser')
onUpdate(newDestinations)
save(selected, newDestinations)
}
const save = useCallback(
debounce(
(
oldDestinations: notification_destination_types[],
newDestinations: notification_destination_types[]
) => {
// for each medium, if it changed, trigger a save
const mediums = ['email', 'browser'] as const
mediums.forEach((medium) => {
const wasEnabled = oldDestinations.includes(medium)
const isEnabled = newDestinations.includes(medium)
if (wasEnabled !== isEnabled) {
api('update-notif-settings', {
type,
medium,
enabled: isEnabled,
})
}
})
},
500
),
[]
)
return (
<div className="flex flex-col gap-2">
<div className="text-ink-700 font-medium">{question}</div>
<MultiSelectAnswers
options={['By email', 'On notifications page']}
values={getSelectedValues(selected)}
setValue={setValue}
/>
</div>
)
}

View File

@@ -4,9 +4,9 @@ import {firebaseLogout} from "web/lib/firebase/users";
import posthog from "posthog-js";
import {clearUserCookie} from "web/components/auth-context";
export async function deleteAccount(username: string) {
export async function deleteAccount() {
track('delete account')
await api('me/delete', {username})
await api('me/delete')
await firebaseLogout()
clearUserCookie()
localStorage.clear()