Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce the "delete account" action #3745

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Reintroduce the "delete account" action
This re-introduces the "Delete Account/Organization" action within the account / organization admin.
  • Loading branch information
Swatinem committed Feb 20, 2025
commit ed8c3c339084c78308db70cb3633e9ef6da22fe8
13 changes: 10 additions & 3 deletions src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import { MemoryRouter, Route } from 'react-router-dom'

import DeletionCard from './DeletionCard'

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})

const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
<MemoryRouter initialEntries={['/account/gh/test-user']}>
<Route path="/account/:provider/:owner">{children}</Route>
</MemoryRouter>
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={['/account/gh/test-user']}>
<Route path="/account/:provider/:owner">{children}</Route>
</MemoryRouter>
</QueryClientProvider>
)

describe('DeletionCard', () => {
91 changes: 74 additions & 17 deletions src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,86 @@
import { useState } from 'react'
import { useParams } from 'react-router-dom'

Check failure on line 3 in src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.tsx

GitHub Actions / Run Lint

Unable to resolve path to module 'services/account'
import Card from 'old_ui/Card'
import A from 'ui/A'
import { useEraseAccount } from 'services/account'

Check failure on line 5 in src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.tsx

GitHub Actions / Run Type Checker

Cannot find module 'services/account' or its corresponding type declarations.

Check failure on line 5 in src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.tsx

GitHub Actions / Upload Bundle Stats - Production

Cannot find module 'services/account' or its corresponding type declarations.

Check failure on line 5 in src/pages/AccountSettings/tabs/DeletionCard/DeletionCard.tsx

GitHub Actions / Upload Bundle Stats - Staging

Cannot find module 'services/account' or its corresponding type declarations.
import Button from 'ui/Button'

import EraseOwnerModal from './EraseOwnerModal'

interface DeletionCardProps {
isPersonalSettings: boolean
}

interface EraseOwnerButtonProps {
isPersonalSettings: boolean
isLoading: boolean
setShowModal: (_: boolean) => void
}

function EraseOwnerButton({
isPersonalSettings,
isLoading,
setShowModal,
}: EraseOwnerButtonProps) {
const button = isPersonalSettings
? 'Erase Personal Account'
: 'Erase Organization'

if (isLoading) {
return (
<div className="font-light italic">
processing erase, this may take a while
</div>
)
}

return (
<Button
variant="danger"
hook="show-modal"
onClick={() => setShowModal(true)}
>
{button}
</Button>
)
}

interface URLParams {
provider?: string
owner?: string
}

function DeletionCard({ isPersonalSettings }: DeletionCardProps) {
const { provider, owner } = useParams<URLParams>()
const [showModal, setShowModal] = useState(false)
const { mutate: eraseOwner, isLoading } = useEraseAccount({ provider, owner })

const title = isPersonalSettings ? 'Delete account' : 'Delete organization'
const text = isPersonalSettings
? 'Erase my personal account and all my repositories.'
: 'Erase organization and all its repositories.'

return (
<div className="flex flex-col gap-4">
<h2 className="text-lg font-semibold">
{isPersonalSettings ? 'Delete account' : 'Delete organization'}
</h2>
<Card>
<p>
{isPersonalSettings
? 'Erase my personal account and all my repositories. '
: 'Erase organization and all its repositories. '}
<A
to={{ pageName: 'support' }}
hook="contact-support-link"
isExternal
>
Contact support
</A>
</p>
<h2 className="text-lg font-semibold">{title}</h2>
<Card className="flex flex-col sm:flex-row">
<div className="flex flex-1 flex-col gap-1">
<p> {text} </p>
</div>
<div>
<EraseOwnerButton
isPersonalSettings={isPersonalSettings}
isLoading={isLoading}
setShowModal={setShowModal}
/>
<EraseOwnerModal
isPersonalSettings={isPersonalSettings}
isLoading={isLoading}
showModal={showModal}
closeModal={() => setShowModal(false)}
eraseOwner={eraseOwner}
/>
</div>
</Card>
</div>
)
65 changes: 65 additions & 0 deletions src/pages/AccountSettings/tabs/DeletionCard/EraseOwnerModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Button from 'ui/Button'
import Modal from 'ui/Modal'

interface EraseOwnerModelProps {
isPersonalSettings: boolean
isLoading: boolean
showModal: boolean
closeModal: () => void
eraseOwner: () => void
}

function EraseOwnerModal({
isPersonalSettings,
closeModal,
eraseOwner,
isLoading,
showModal,
}: EraseOwnerModelProps) {
const title = isPersonalSettings
? 'Are you sure you want to delete your personal account?'
: 'Are you sure you want to erase this organization?'
let text = isPersonalSettings
? 'This action will delete all personal data, including login information and personal tokens.'
: 'This action will delete all organization content and associated tokens.'
text +=
' It will also erase all of the repositories, including all of their contents.'
text +=
' This action is irreversible and if you proceed, you will permanently erase all of the associated content.'
const button = isPersonalSettings
? 'Erase Personal Account'
: 'Erase Organization'

return (
<Modal
isOpen={showModal}
onClose={closeModal}
title={title}
body={<p>{text}</p>}
footer={
<div className="flex gap-2">
<div>
<Button hook="close-modal" onClick={closeModal}>
Cancel
</Button>
</div>
<div>
<Button
isLoading={isLoading}
hook="erase-owner-content"
variant="danger"
onClick={async () => {
await eraseOwner()
closeModal()
}}
>
{button}
</Button>
</div>
</div>
}
/>
)
}

export default EraseOwnerModal
Loading
Oops, something went wrong.