Add account deletion functionality (#4153)

* chore: delete account

* Add account deletion functionality

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
pull/4159/head
Arik Chakma 1 year ago committed by GitHub
parent 2d3a89bd56
commit 8a5bc21206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1829
      pnpm-lock.yaml
  2. 8
      src/components/AccountSidebar.astro
  3. 2
      src/components/Authenticator/authenticator.ts
  4. 16
      src/components/DeleteAccount/DeleteAccount.astro
  5. 89
      src/components/DeleteAccount/DeleteAccountForm.tsx
  6. 17
      src/components/DeleteAccount/DeleteAccountPopup.astro
  7. 4
      src/icons/cog.svg
  8. 9
      src/pages/account/settings.astro

File diff suppressed because it is too large Load Diff

@ -40,12 +40,12 @@ const sidebarLinks = [
}, },
}, },
{ {
href: '/account/update-password', href: '/account/settings',
title: 'Security', title: 'Settings',
id: 'change-password', id: 'settings',
isNew: false, isNew: false,
icon: { icon: {
glyph: 'security', glyph: 'cog',
classes: 'h-4 w-4', classes: 'h-4 w-4',
}, },
}, },

@ -33,7 +33,7 @@ function showHideGuestElements(hideOrShow: 'hide' | 'show' = 'hide') {
function handleGuest() { function handleGuest() {
const authenticatedRoutes = [ const authenticatedRoutes = [
'/account/update-profile', '/account/update-profile',
'/account/update-password', '/account/settings',
'/account/road-card', '/account/road-card',
'/account', '/account',
]; ];

@ -0,0 +1,16 @@
---
import DeleteAccountPopup from "./DeleteAccountPopup.astro";
---
<DeleteAccountPopup />
<h2 class='text-xl font-bold sm:text-2xl'>Delete Account</h2>
<p class='mt-2 text-gray-400'>
Permanently remove your account from the roadmap.sh. This cannot be undone and all your progress and data will be lost.
</p>
<button
data-popup='delete-account-popup'
class="mt-4 w-full rounded-lg bg-red-600 py-2 text-base font-regular text-white outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-1"
>
Delete Account
</button>

@ -0,0 +1,89 @@
import {useEffect, useState} from 'preact/hooks';
import { httpDelete } from '../../lib/http';
import { logout } from '../Navigation/navigation';
export function DeleteAccountForm() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [confirmationText, setConfirmationText] = useState('');
useEffect(() => {
setError('');
setConfirmationText('');
}, [])
const handleSubmit = async (e: Event) => {
e.preventDefault();
setIsLoading(true);
setError('');
if (confirmationText.toUpperCase() !== 'DELETE') {
setError('Verification text does not match');
setIsLoading(false);
return;
}
const { response, error } = await httpDelete(
`${import.meta.env.PUBLIC_API_URL}/v1-delete-account`
);
if (error || !response) {
setIsLoading(false);
setError(error?.message || 'Something went wrong');
return;
}
logout();
};
const handleClosePopup = () => {
setIsLoading(false);
setError('');
setConfirmationText('');
const deleteAccountPopup = document.getElementById('delete-account-popup');
deleteAccountPopup?.classList.add('hidden');
deleteAccountPopup?.classList.remove('flex');
};
return (
<form onSubmit={handleSubmit}>
<div className="my-4">
<input
type="text"
name="delete-account"
id="delete-account"
className="mt-2 block w-full rounded-md border border-gray-300 py-2 px-3 outline-none placeholder:text-gray-400 focus:border-gray-400"
placeholder={'Type "delete" to confirm'}
required
autoFocus
value={confirmationText}
onInput={(e) =>
setConfirmationText((e.target as HTMLInputElement).value)
}
/>
{error && (
<p className="mt-2 rounded-lg bg-red-100 p-2 text-red-700">{error}</p>
)}
</div>
<div className="flex items-center gap-2">
<button
type="button"
disabled={isLoading}
onClick={handleClosePopup}
className="flex-grow cursor-pointer rounded-lg bg-gray-200 py-2 text-center"
>
Cancel
</button>
<button
type="submit"
disabled={isLoading || confirmationText.toUpperCase() !== 'DELETE'}
className="flex-grow cursor-pointer rounded-lg bg-red-500 py-2 text-white disabled:opacity-40"
>
{isLoading ? 'Please wait ..' : 'Confirm'}
</button>
</div>
</form>
);
}

@ -0,0 +1,17 @@
---
import Popup from '../Popup/Popup.astro';
import { DeleteAccountForm } from './DeleteAccountForm';
---
<Popup id='delete-account-popup' title='Delete Account' subtitle=''>
<div class='-mt-2.5'>
<p>
This will permanently delete your account and all your associated data
including your progress.
</p>
<p class="text-black font-medium -mb-2 mt-3 text-base">Please type "delete" to confirm.</p>
<DeleteAccountForm client:only />
</div>
</Popup>

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -2,15 +2,18 @@
import AccountSidebar from '../../components/AccountSidebar.astro'; import AccountSidebar from '../../components/AccountSidebar.astro';
import UpdatePasswordForm from '../../components/UpdatePassword/UpdatePasswordForm'; import UpdatePasswordForm from '../../components/UpdatePassword/UpdatePasswordForm';
import AccountLayout from '../../layouts/AccountLayout.astro'; import AccountLayout from '../../layouts/AccountLayout.astro';
import DeleteAccount from '../../components/DeleteAccount/DeleteAccount.astro';
--- ---
<AccountLayout <AccountLayout
title='Change Password' title='Settings'
description='' description=''
noIndex={true} noIndex={true}
initialLoadingMessage={'Loading profile'} initialLoadingMessage={'Loading settings'}
> >
<AccountSidebar activePageId='change-password' activePageTitle='Change Password'> <AccountSidebar activePageId='settings' activePageTitle='Settings'>
<UpdatePasswordForm client:load /> <UpdatePasswordForm client:load />
<hr class='my-8' />
<DeleteAccount />
</AccountSidebar> </AccountSidebar>
</AccountLayout> </AccountLayout>
Loading…
Cancel
Save