parent
37107c495f
commit
8a94609fb9
8 changed files with 202 additions and 21 deletions
@ -0,0 +1,54 @@ |
|||||||
|
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> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
import { useState } from 'preact/hooks'; |
||||||
|
import Cookies from 'js-cookie'; |
||||||
|
import { httpDelete } from '../../lib/http'; |
||||||
|
import { TOKEN_COOKIE_NAME } from '../../lib/jwt'; |
||||||
|
import { hideDeleteAccountPopup } from './DeleteAccount'; |
||||||
|
|
||||||
|
const DELETE_ACCOUNT_VERIFICATION = 'delete my account'; |
||||||
|
|
||||||
|
export function DeleteAccountForm() { |
||||||
|
const [isLoading, setIsLoading] = useState(false); |
||||||
|
const [error, setError] = useState(''); |
||||||
|
const [deleteAccount, setDeleteAccount] = useState(''); |
||||||
|
|
||||||
|
const handleSubmit = async (e: Event) => { |
||||||
|
e.preventDefault(); |
||||||
|
setIsLoading(true); |
||||||
|
setError(''); |
||||||
|
|
||||||
|
if (deleteAccount !== DELETE_ACCOUNT_VERIFICATION) { |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
Cookies.remove(TOKEN_COOKIE_NAME); |
||||||
|
window.location.href = '/'; |
||||||
|
}; |
||||||
|
|
||||||
|
const handleClosePopup = () => { |
||||||
|
setIsLoading(false); |
||||||
|
setError(''); |
||||||
|
setDeleteAccount(''); |
||||||
|
|
||||||
|
hideDeleteAccountPopup(); |
||||||
|
}; |
||||||
|
|
||||||
|
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> |
||||||
|
<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" |
||||||
|
required |
||||||
|
autoFocus |
||||||
|
value={deleteAccount} |
||||||
|
onInput={(e) => |
||||||
|
setDeleteAccount((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="mt-6 flex items-center justify-between 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" |
||||||
|
> |
||||||
|
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" |
||||||
|
> |
||||||
|
{isLoading ? 'Please wait...' : 'Delete Account'} |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
--- |
||||||
|
import Popup from '../Popup/Popup.astro'; |
||||||
|
import { DeleteAccountForm } from './DeleteAccountForm'; |
||||||
|
--- |
||||||
|
|
||||||
|
<Popup id='delete-account-popup' title='' 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> |
||||||
|
|
||||||
|
<div class='mt-6 flex flex-col gap-1.5'> |
||||||
|
<DeleteAccountForm client:load /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</Popup> |
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,22 @@ |
|||||||
|
--- |
||||||
|
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'; |
||||||
|
--- |
||||||
|
|
||||||
|
<AccountLayout |
||||||
|
title='Settings' |
||||||
|
description='' |
||||||
|
noIndex={true} |
||||||
|
initialLoadingMessage={'Loading settings'} |
||||||
|
> |
||||||
|
<AccountSidebar activePageId='settings' activePageTitle='Settings'> |
||||||
|
<UpdatePasswordForm client:load /> |
||||||
|
<hr class='my-10' /> |
||||||
|
<DeleteAccount client:load /> |
||||||
|
</AccountSidebar> |
||||||
|
|
||||||
|
<DeleteAccountPopup /> |
||||||
|
</AccountLayout> |
@ -1,16 +0,0 @@ |
|||||||
--- |
|
||||||
import AccountSidebar from '../../components/AccountSidebar.astro'; |
|
||||||
import UpdatePasswordForm from '../../components/UpdatePassword/UpdatePasswordForm'; |
|
||||||
import AccountLayout from '../../layouts/AccountLayout.astro'; |
|
||||||
--- |
|
||||||
|
|
||||||
<AccountLayout |
|
||||||
title='Change Password' |
|
||||||
description='' |
|
||||||
noIndex={true} |
|
||||||
initialLoadingMessage={'Loading profile'} |
|
||||||
> |
|
||||||
<AccountSidebar activePageId='change-password' activePageTitle='Change Password'> |
|
||||||
<UpdatePasswordForm client:load /> |
|
||||||
</AccountSidebar> |
|
||||||
</AccountLayout> |
|
Loading…
Reference in new issue