Add account deletion functionality

chore/delete-account
Kamran Ahmed 1 year ago
parent 8a94609fb9
commit d1aa0983b6
  1. 1833
      pnpm-lock.yaml
  2. 16
      src/components/DeleteAccount/DeleteAccount.astro
  3. 54
      src/components/DeleteAccount/DeleteAccount.tsx
  4. 52
      src/components/DeleteAccount/DeleteAccountForm.tsx
  5. 21
      src/components/DeleteAccount/DeleteAccountPopup.astro
  6. 9
      src/pages/account/settings.astro

File diff suppressed because it is too large Load Diff

@ -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>

@ -1,54 +0,0 @@
export function showDeleteAccountPopup() {
const popupEl = document.querySelector(`#delete-account-popup`);
if (!popupEl) {
return;
}
popupEl.classList.remove('hidden');
popupEl.classList.add('flex');
const focusEl = popupEl.querySelector<HTMLElement>('[autofocus]');
if (focusEl) {
focusEl.focus();
}
}
export function hideDeleteAccountPopup() {
const popupEl = document.querySelector(`#delete-account-popup`);
if (!popupEl) {
return;
}
popupEl.classList.remove('flex');
popupEl.classList.add('hidden');
const focusEl = popupEl.querySelector<HTMLElement>('[autofocus]');
if (focusEl) {
focusEl.blur();
}
}
export function DeleteAccount() {
return (
<div>
<div>
<h2 className="text-xl font-bold sm:text-2xl">
Delete Account
</h2>
<p className="mt-2 text-gray-400">
Permanently remove your account from the roadmap.sh. This action is
not reversible, so please continue with caution.
</p>
</div>
<div className="mt-4">
<button
className="inline-flex h-10 items-center justify-center rounded-md bg-red-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-500/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-red-200 disabled:pointer-events-none disabled:opacity-50"
onClick={showDeleteAccountPopup}
>
Delete Account
</button>
</div>
</div>
);
}

@ -1,22 +1,23 @@
import { useState } from 'preact/hooks';
import Cookies from 'js-cookie';
import {useEffect, useState} from 'preact/hooks';
import { httpDelete } from '../../lib/http';
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
import { hideDeleteAccountPopup } from './DeleteAccount';
const DELETE_ACCOUNT_VERIFICATION = 'delete my account';
import { logout } from '../Navigation/navigation';
export function DeleteAccountForm() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [deleteAccount, setDeleteAccount] = useState('');
const [confirmationText, setConfirmationText] = useState('');
useEffect(() => {
setError('');
setConfirmationText('');
}, [])
const handleSubmit = async (e: Event) => {
e.preventDefault();
setIsLoading(true);
setError('');
if (deleteAccount !== DELETE_ACCOUNT_VERIFICATION) {
if (confirmationText.toUpperCase() !== 'DELETE') {
setError('Verification text does not match');
setIsLoading(false);
return;
@ -32,38 +33,33 @@ export function DeleteAccountForm() {
return;
}
Cookies.remove(TOKEN_COOKIE_NAME);
window.location.href = '/';
logout();
};
const handleClosePopup = () => {
setIsLoading(false);
setError('');
setDeleteAccount('');
setConfirmationText('');
hideDeleteAccountPopup();
const deleteAccountPopup = document.getElementById('delete-account-popup');
deleteAccountPopup?.classList.add('hidden');
deleteAccountPopup?.classList.remove('flex');
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="delete-account" className="text-sm text-gray-500">
To verify, type{' '}
<span className="font-medium text-gray-600">
{DELETE_ACCOUNT_VERIFICATION}
</span>{' '}
below:
</label>
<div className="my-4">
<input
type="text"
name="delete-account"
id="delete-account"
className="mt-2 block w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1"
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={deleteAccount}
value={confirmationText}
onInput={(e) =>
setDeleteAccount((e.target as HTMLInputElement).value)
setConfirmationText((e.target as HTMLInputElement).value)
}
/>
{error && (
@ -71,21 +67,21 @@ export function DeleteAccountForm() {
)}
</div>
<div className="mt-6 flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
<button
type="button"
disabled={isLoading}
onClick={handleClosePopup}
className="flex h-10 items-center justify-center rounded-md bg-gray-100 px-4 py-2 text-sm font-medium text-black shadow-sm hover:bg-gray-100/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-200 disabled:pointer-events-none disabled:opacity-50"
className="flex-grow cursor-pointer rounded-lg bg-gray-200 py-2 text-center"
>
Cancel
</button>
<button
type="submit"
disabled={isLoading}
className="flex h-10 items-center justify-center rounded-md bg-red-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-500/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-red-200 disabled:pointer-events-none disabled:opacity-50"
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...' : 'Delete Account'}
{isLoading ? 'Please wait ..' : 'Confirm'}
</button>
</div>
</form>

@ -3,22 +3,15 @@ import Popup from '../Popup/Popup.astro';
import { DeleteAccountForm } from './DeleteAccountForm';
---
<Popup id='delete-account-popup' title='' subtitle=''>
<Popup id='delete-account-popup' title='Delete Account' subtitle=''>
<div class='-mt-2.5'>
<h2 class='mb-3 text-2xl font-semibold leading-5 text-gray-900'>
Delete Account
</h2>
<p class='text-sm text-gray-600'>
Deleting your account will remove all your data from our servers
(including your progress).
</p>
<p class='rounded-md bg-yellow-300 p-2 text-xs text-yellow-800 mt-6'>
<span class='font-medium'>Warning:</span> This action is not reversible. Please
be certain.
<p>
This will permanently delete your account and all your associated data
including your progress.
</p>
<div class='mt-6 flex flex-col gap-1.5'>
<DeleteAccountForm client:load />
</div>
<p class="text-black font-medium -mb-2 mt-3 text-base">Please type "delete" to confirm.</p>
<DeleteAccountForm client:only />
</div>
</Popup>

@ -2,8 +2,7 @@
import AccountSidebar from '../../components/AccountSidebar.astro';
import UpdatePasswordForm from '../../components/UpdatePassword/UpdatePasswordForm';
import AccountLayout from '../../layouts/AccountLayout.astro';
import { DeleteAccount } from '../../components/DeleteAccount/DeleteAccount';
import DeleteAccountPopup from '../../components/DeleteAccount/DeleteAccountPopup.astro';
import DeleteAccount from '../../components/DeleteAccount/DeleteAccount.astro';
---
<AccountLayout
@ -14,9 +13,7 @@ import DeleteAccountPopup from '../../components/DeleteAccount/DeleteAccountPopu
>
<AccountSidebar activePageId='settings' activePageTitle='Settings'>
<UpdatePasswordForm client:load />
<hr class='my-10' />
<DeleteAccount client:load />
<hr class='my-8' />
<DeleteAccount />
</AccountSidebar>
<DeleteAccountPopup />
</AccountLayout>

Loading…
Cancel
Save