pronounss/frontend/src/routes/auth/login/CallbackPage.svelte

216 lines
6.4 KiB
Svelte

<script lang="ts">
import { goto } from "$app/navigation";
import type { APIError, MeUser } from "$lib/api/entities";
import { apiFetch } from "$lib/api/fetch";
import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import { userStore } from "$lib/store";
import { addToast } from "$lib/toast";
import { DateTime } from "luxon";
import { onMount } from "svelte";
import {
Alert,
Button,
FormGroup,
Icon,
Input,
Modal,
ModalBody,
ModalFooter,
} from "sveltestrap";
export let authType: string;
export let remoteName: string | undefined;
export let error: APIError | undefined;
export let requireInvite: boolean | undefined;
export let isDeleted: boolean | undefined;
export let ticket: string | undefined;
export let token: string | undefined;
export let user: MeUser | undefined;
export let deletedAt: string | undefined;
export let selfDelete: boolean | undefined;
export let deleteReason: string | undefined;
onMount(() => {
if (!isDeleted && token && user) {
localStorage.setItem("pronouns-token", token);
localStorage.setItem("pronouns-user", JSON.stringify(user));
userStore.set(user);
goto("/");
}
});
let deleteCancelled: boolean;
let deleteError: APIError | null;
let username: string;
let inviteCode: string;
let forceDeleteName = "";
let forceDeleteModalOpen = false;
let toggleForceDeleteModal = () => (forceDeleteModalOpen = !forceDeleteModalOpen);
export let linkAccount: () => Promise<void>;
export let signupForm: (username: string, inviteCode: string) => Promise<void>;
const forceDeleteAccount = async () => {
try {
await apiFetch<any>("/auth/force-delete", {
method: "GET",
headers: {
"X-Delete-Token": token!,
},
});
deleteError = null;
addToast({ header: "Deleted account", body: "Successfully deleted your account" });
goto("/");
} catch (e) {
deleteError = e as APIError;
}
};
const cancelDelete = async () => {
try {
await apiFetch<any>("/auth/cancel-delete", {
method: "GET",
headers: {
"X-Delete-Token": token!,
},
});
deleteCancelled = true;
deleteError = null;
} catch (e) {
deleteCancelled = false;
deleteError = e as APIError;
}
};
</script>
<svelte:head>
<title>Log in with the {authType} - pronouns.cc</title>
</svelte:head>
<h1>Log in with the {authType}</h1>
{#if error}
<ErrorAlert {error} />
{/if}
{#if ticket && $userStore}
<div>
<FormGroup floating label="{authType} username">
<Input readonly value={remoteName} />
</FormGroup>
</div>
<div class="my-2">
<FormGroup floating label="pronouns.cc username">
<Input readonly value={$userStore.name} />
</FormGroup>
</div>
<div>
<Button on:click={linkAccount}>Link account</Button>
<Button color="secondary" href="/settings/auth">Cancel</Button>
</div>
{:else if ticket}
<form on:submit|preventDefault={() => signupForm(username, inviteCode)}>
<div>
<FormGroup floating label="{authType} username">
<Input readonly value={remoteName} />
</FormGroup>
</div>
<div>
<FormGroup floating label="Username">
<Input id="username" name="username" bind:value={username} />
</FormGroup>
</div>
{#if requireInvite}
<div>
<FormGroup floating label="Invite code">
<Input id="invite" name="invite" aria-describedby="invite-help" bind:value={inviteCode} />
</FormGroup>
<div id="invite-help" class="form-text">
<Icon name="info-circle-fill" /> You currently need an invite code to sign up. You can get
one from an existing user.
</div>
</div>
{/if}
<div class="form-text mb-1">
By signing up, you agree to the <a href="/page/tos">terms of service</a> and the
<a href="/page/privacy">privacy policy</a>.
</div>
<Button type="submit" color="primary">Sign up</Button>
</form>
{:else if isDeleted && token && selfDelete && deletedAt}
<p>
Your account is pending deletion since {DateTime.fromISO(deletedAt)
.toLocal()
.toLocaleString(DateTime.DATETIME_MED)}.
</p>
<p>If you wish to cancel deletion, press the button below.</p>
<p>
<Button color="primary" on:click={cancelDelete} disabled={deleteCancelled}
>Cancel account deletion</Button
>
</p>
<p>
Alternatively, if you want your data wiped immediately, press the force delete link below. <b
>This is irreversible.</b
>
</p>
<p>
<Button color="link" on:click={toggleForceDeleteModal}>Force delete account</Button>
</p>
{#if deleteCancelled}
<Alert color="secondary" fade={false}>
Account deletion cancelled! You can now <a href="/auth/login">log in</a> again.
</Alert>
{/if}
{#if deleteError}
<ErrorAlert error={deleteError} />
{/if}
{:else if isDeleted && token && !selfDelete && deletedAt}
<p>
Your account is pending deletion since {DateTime.fromISO(deletedAt)
.toLocal()
.toLocaleString(DateTime.DATETIME_MED)}.
</p>
<p>
<strong>Your account was deactivated by a moderator.</strong> You cannot cancel deletion. The moderator
gave the following reason:
</p>
<blockquote class="blockquote">
{deleteReason}
</blockquote>
<p>
Your account will be fully deleted 180 days after being deactivated. If you want your data wiped
immediately instead, press the force delete link below.
</p>
<p>
<Button color="link" on:click={toggleForceDeleteModal}>Force delete account</Button>
</p>
{:else}
Loading...
{/if}
<Modal header="Force delete account" isOpen={forceDeleteModalOpen} toggle={toggleForceDeleteModal}>
<ModalBody>
<p>
If you want to delete your account, type your username (<code>{user?.name}</code>) below:
<br />
<b>
This is irreversible! Your account <i>cannot</i> be recovered after you press "Force delete account".
</b>
</p>
<p>
<input type="text" class="form-control" bind:value={forceDeleteName} />
</p>
{#if deleteError}
<ErrorAlert error={deleteError} />
{/if}
</ModalBody>
<ModalFooter>
<Button color="danger" on:click={forceDeleteAccount} disabled={forceDeleteName !== user?.name}
>Force delete account</Button
>
<Button color="secondary" on:click={toggleForceDeleteModal}>Cancel delete</Button>
</ModalFooter>
</Modal>