2024-07-08 11:44:39 -04:00
|
|
|
<script lang="ts">
|
|
|
|
import { enhance } from '$app/forms';
|
|
|
|
import { page } from '$app/stores';
|
|
|
|
import { addToast } from '$lib/toasts';
|
2024-10-29 10:29:03 -04:00
|
|
|
import type { User } from '$lib/types.js';
|
2024-07-08 11:44:39 -04:00
|
|
|
import { onMount } from 'svelte';
|
|
|
|
import { browser } from '$app/environment';
|
2024-10-29 10:29:03 -04:00
|
|
|
import { t } from 'svelte-i18n';
|
2024-12-13 10:48:18 -05:00
|
|
|
import TotpModal from '$lib/components/TOTPModal.svelte';
|
2024-07-08 11:44:39 -04:00
|
|
|
|
|
|
|
export let data;
|
|
|
|
let user: User;
|
2024-12-07 16:15:41 -05:00
|
|
|
let emails: typeof data.props.emails;
|
2024-07-08 11:44:39 -04:00
|
|
|
if (data.user) {
|
|
|
|
user = data.user;
|
2024-12-07 16:15:41 -05:00
|
|
|
emails = data.props.emails;
|
2024-07-08 11:44:39 -04:00
|
|
|
}
|
|
|
|
|
2024-12-11 20:46:20 -05:00
|
|
|
let new_email: string = '';
|
|
|
|
|
2024-12-13 20:21:44 -05:00
|
|
|
let isMFAModalOpen: boolean = false;
|
2024-12-13 10:48:18 -05:00
|
|
|
|
2024-07-08 11:44:39 -04:00
|
|
|
onMount(async () => {
|
|
|
|
if (browser) {
|
|
|
|
const queryParams = new URLSearchParams($page.url.search);
|
|
|
|
const pageParam = queryParams.get('page');
|
|
|
|
|
|
|
|
if (pageParam === 'success') {
|
2024-10-29 10:29:03 -04:00
|
|
|
addToast('success', $t('settings.update_success'));
|
2024-07-08 11:44:39 -04:00
|
|
|
console.log('Settings updated successfully!');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$: {
|
|
|
|
if (browser && $page.form?.success) {
|
|
|
|
window.location.href = '/settings?page=success';
|
|
|
|
}
|
|
|
|
if (browser && $page.form?.error) {
|
2024-10-29 10:29:03 -04:00
|
|
|
addToast('error', $t('settings.update_error'));
|
2024-07-08 11:44:39 -04:00
|
|
|
}
|
|
|
|
}
|
2024-07-16 21:24:18 -04:00
|
|
|
|
2024-11-01 20:08:23 -04:00
|
|
|
async function checkVisitedRegions() {
|
|
|
|
let res = await fetch('/api/reverse-geocode/mark_visited_region/', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let data = await res.json();
|
|
|
|
if (res.ok) {
|
2024-11-01 20:12:43 -04:00
|
|
|
addToast('success', `${data.new_regions} ${$t('adventures.regions_updated')}`);
|
2024-11-01 20:08:23 -04:00
|
|
|
} else {
|
2024-11-01 20:12:43 -04:00
|
|
|
addToast('error', $t('adventures.error_updating_regions'));
|
2024-11-01 20:08:23 -04:00
|
|
|
}
|
|
|
|
}
|
2024-12-07 16:15:41 -05:00
|
|
|
|
|
|
|
async function removeEmail(email: { email: any; verified?: boolean; primary?: boolean }) {
|
|
|
|
let res = await fetch('/_allauth/browser/v1/account/email/', {
|
|
|
|
method: 'DELETE',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email: email.email })
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('success', $t('settings.email_removed'));
|
2024-12-07 16:15:41 -05:00
|
|
|
emails = emails.filter((e) => e.email !== email.email);
|
|
|
|
} else {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('error', $t('settings.email_removed_error'));
|
2024-12-07 16:15:41 -05:00
|
|
|
}
|
|
|
|
}
|
2024-12-11 20:46:20 -05:00
|
|
|
|
|
|
|
async function verifyEmail(email: { email: any; verified?: boolean; primary?: boolean }) {
|
|
|
|
let res = await fetch('/_allauth/browser/v1/account/email/', {
|
|
|
|
method: 'PUT',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email: email.email })
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('success', $t('settings.verify_email_success'));
|
2024-12-11 20:46:20 -05:00
|
|
|
} else {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('error', $t('settings.verify_email_error'));
|
2024-12-11 20:46:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function addEmail() {
|
|
|
|
let res = await fetch('/_allauth/browser/v1/account/email/', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email: new_email })
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('success', $t('settings.email_added'));
|
2024-12-11 20:46:20 -05:00
|
|
|
emails = [...emails, { email: new_email, verified: false, primary: false }];
|
|
|
|
new_email = '';
|
|
|
|
} else {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('error', $t('settings.email_added_error'));
|
2024-12-11 20:46:20 -05:00
|
|
|
}
|
|
|
|
}
|
2024-12-12 11:01:09 -05:00
|
|
|
|
|
|
|
async function primaryEmail(email: { email: any; verified?: boolean; primary?: boolean }) {
|
|
|
|
let res = await fetch('/_allauth/browser/v1/account/email/', {
|
|
|
|
method: 'PATCH',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email: email.email, primary: true })
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('success', $t('settings.email_set_primary'));
|
2024-12-12 11:01:09 -05:00
|
|
|
// remove primary from all other emails and set this one as primary
|
|
|
|
emails = emails.map((e) => {
|
|
|
|
if (e.email === email.email) {
|
|
|
|
e.primary = true;
|
|
|
|
} else {
|
|
|
|
e.primary = false;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
});
|
|
|
|
} else {
|
2024-12-12 19:20:58 -05:00
|
|
|
addToast('error', $t('settings.email_set_primary_error'));
|
2024-12-12 11:01:09 -05:00
|
|
|
}
|
|
|
|
}
|
2024-12-13 10:48:18 -05:00
|
|
|
|
|
|
|
async function disableMfa() {
|
|
|
|
const res = await fetch('/_allauth/browser/v1/account/authenticators/totp', {
|
|
|
|
method: 'DELETE'
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2024-12-13 20:21:44 -05:00
|
|
|
addToast('success', $t('settings.mfa_disabled'));
|
2024-12-13 10:48:18 -05:00
|
|
|
data.props.authenticators = false;
|
|
|
|
} else {
|
|
|
|
if (res.status == 401) {
|
2024-12-13 20:21:44 -05:00
|
|
|
addToast('error', $t('settings.reset_session_error'));
|
2024-12-13 10:48:18 -05:00
|
|
|
}
|
|
|
|
addToast('error', $t('settings.generic_error'));
|
|
|
|
}
|
|
|
|
}
|
2024-07-08 11:44:39 -04:00
|
|
|
</script>
|
|
|
|
|
2024-12-13 20:21:44 -05:00
|
|
|
{#if isMFAModalOpen}
|
2024-12-13 10:48:18 -05:00
|
|
|
<TotpModal
|
|
|
|
user={data.user}
|
2024-12-13 20:21:44 -05:00
|
|
|
on:close={() => (isMFAModalOpen = false)}
|
2024-12-13 10:48:18 -05:00
|
|
|
bind:is_enabled={data.props.authenticators}
|
|
|
|
/>
|
|
|
|
{/if}
|
|
|
|
|
2024-10-29 10:29:03 -04:00
|
|
|
<h1 class="text-center font-extrabold text-4xl mb-6">{$t('settings.settings_page')}</h1>
|
2024-07-08 11:44:39 -04:00
|
|
|
|
2024-10-29 10:29:03 -04:00
|
|
|
<h1 class="text-center font-extrabold text-xl">{$t('settings.account_settings')}</h1>
|
2024-07-08 11:44:39 -04:00
|
|
|
<div class="flex justify-center">
|
|
|
|
<form
|
|
|
|
method="post"
|
|
|
|
action="?/changeDetails"
|
|
|
|
use:enhance
|
|
|
|
class="w-full max-w-xs"
|
|
|
|
enctype="multipart/form-data"
|
|
|
|
>
|
2024-10-29 10:29:03 -04:00
|
|
|
<label for="username">{$t('auth.username')}</label>
|
2024-07-08 11:44:39 -04:00
|
|
|
<input
|
|
|
|
bind:value={user.username}
|
|
|
|
name="username"
|
|
|
|
id="username"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/><br />
|
2024-10-29 10:29:03 -04:00
|
|
|
<label for="first_name">{$t('auth.first_name')}</label>
|
2024-07-08 11:44:39 -04:00
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
bind:value={user.first_name}
|
|
|
|
name="first_name"
|
|
|
|
id="first_name"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/><br />
|
|
|
|
|
2024-10-29 10:29:03 -04:00
|
|
|
<label for="last_name">{$t('auth.last_name')}</label>
|
2024-07-08 11:44:39 -04:00
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
bind:value={user.last_name}
|
|
|
|
name="last_name"
|
|
|
|
id="last_name"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/><br />
|
2024-10-29 10:29:03 -04:00
|
|
|
<label for="profilePicture">{$t('auth.profile_picture')}</label>
|
2024-07-08 11:44:39 -04:00
|
|
|
<input
|
|
|
|
type="file"
|
|
|
|
name="profile_pic"
|
|
|
|
id="profile_pic"
|
|
|
|
class="file-input file-input-bordered w-full max-w-xs mb-2"
|
|
|
|
/><br />
|
2024-09-08 13:53:50 -04:00
|
|
|
<div class="form-control">
|
2024-10-29 10:29:03 -04:00
|
|
|
<div class="tooltip tooltip-info" data-tip={$t('auth.public_tooltip')}>
|
2024-09-08 13:53:50 -04:00
|
|
|
<label class="label cursor-pointer">
|
2024-10-29 10:29:03 -04:00
|
|
|
<span class="label-text">{$t('auth.public_profile')}</span>
|
2024-09-08 13:53:50 -04:00
|
|
|
|
|
|
|
<input
|
|
|
|
id="public_profile"
|
|
|
|
name="public_profile"
|
|
|
|
type="checkbox"
|
|
|
|
class="toggle"
|
|
|
|
checked={user.public_profile}
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-10-29 10:29:03 -04:00
|
|
|
<button class="py-2 mt-2 px-4 btn btn-primary">{$t('settings.update')}</button>
|
2024-07-08 11:44:39 -04:00
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{#if $page.form?.message}
|
|
|
|
<div class="text-center text-error mt-4">
|
2024-12-12 19:20:58 -05:00
|
|
|
{$t($page.form.message)}
|
2024-07-08 11:44:39 -04:00
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
|
2024-10-29 10:29:03 -04:00
|
|
|
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.password_change')}</h1>
|
2024-07-08 11:44:39 -04:00
|
|
|
<div class="flex justify-center">
|
2024-11-30 10:24:27 -05:00
|
|
|
<form action="?/changePassword" method="post" class="w-full max-w-xs" use:enhance>
|
|
|
|
<input
|
|
|
|
type="password"
|
|
|
|
name="current_password"
|
|
|
|
placeholder={$t('settings.current_password')}
|
|
|
|
id="current_password"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/>
|
|
|
|
<br />
|
2024-07-08 11:44:39 -04:00
|
|
|
<input
|
|
|
|
type="password"
|
|
|
|
name="password1"
|
2024-10-29 10:29:03 -04:00
|
|
|
placeholder={$t('settings.new_password')}
|
2024-07-08 11:44:39 -04:00
|
|
|
id="password1"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/>
|
|
|
|
<br />
|
|
|
|
<input
|
|
|
|
type="password"
|
|
|
|
name="password2"
|
|
|
|
id="password2"
|
2024-10-29 10:29:03 -04:00
|
|
|
placeholder={$t('settings.confirm_new_password')}
|
2024-07-08 11:44:39 -04:00
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/>
|
2024-12-03 14:00:48 -05:00
|
|
|
<div class="tooltip tooltip-warning" data-tip={$t('settings.password_change_lopout_warning')}>
|
|
|
|
<button class="py-2 px-4 btn btn-primary mt-2">{$t('settings.password_change')}</button>
|
|
|
|
</div>
|
2024-07-08 11:44:39 -04:00
|
|
|
<br />
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
|
2024-10-29 10:29:03 -04:00
|
|
|
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.email_change')}</h1>
|
2024-12-11 20:46:20 -05:00
|
|
|
|
|
|
|
<div class="flex justify-center mb-4">
|
2024-12-07 16:15:41 -05:00
|
|
|
<div>
|
|
|
|
{#each emails as email}
|
2024-12-11 20:46:20 -05:00
|
|
|
<p class="mb-2">
|
2024-12-07 16:15:41 -05:00
|
|
|
{email.email}
|
2024-12-11 20:46:20 -05:00
|
|
|
{#if email.verified}
|
2024-12-12 19:20:58 -05:00
|
|
|
<div class="badge badge-success">{$t('settings.verified')}</div>
|
2024-12-11 20:46:20 -05:00
|
|
|
{:else}
|
2024-12-12 19:20:58 -05:00
|
|
|
<div class="badge badge-error">{$t('settings.not_verified')}</div>
|
2024-12-11 20:46:20 -05:00
|
|
|
{/if}
|
|
|
|
{#if email.primary}
|
2024-12-12 19:20:58 -05:00
|
|
|
<div class="badge badge-primary">{$t('settings.primary')}</div>
|
2024-12-11 20:46:20 -05:00
|
|
|
{/if}
|
|
|
|
{#if !email.verified}
|
|
|
|
<button class="btn btn-sm btn-secondary ml-2" on:click={() => verifyEmail(email)}
|
2024-12-12 19:20:58 -05:00
|
|
|
>{$t('settings.verify')}</button
|
2024-12-11 20:46:20 -05:00
|
|
|
>
|
|
|
|
{/if}
|
2024-12-12 11:01:09 -05:00
|
|
|
{#if !email.primary}
|
|
|
|
<button class="btn btn-sm btn-secondary ml-2" on:click={() => primaryEmail(email)}
|
2024-12-12 19:20:58 -05:00
|
|
|
>{$t('settings.make_primary')}</button
|
2024-12-12 11:01:09 -05:00
|
|
|
>
|
|
|
|
{/if}
|
|
|
|
<button class="btn btn-sm btn-warning ml-2" on:click={() => removeEmail(email)}
|
2024-12-12 19:20:58 -05:00
|
|
|
>{$t('adventures.remove')}</button
|
2024-12-12 11:01:09 -05:00
|
|
|
>
|
2024-12-07 16:15:41 -05:00
|
|
|
</p>
|
|
|
|
{/each}
|
|
|
|
{#if emails.length === 0}
|
2024-12-12 19:20:58 -05:00
|
|
|
<p>{$t('settings.no_emai_set')}</p>
|
2024-12-07 16:15:41 -05:00
|
|
|
{/if}
|
|
|
|
</div>
|
2024-12-11 20:46:20 -05:00
|
|
|
</div>
|
2024-12-07 16:15:41 -05:00
|
|
|
|
2024-12-11 20:46:20 -05:00
|
|
|
<div class="flex justify-center mt-4">
|
|
|
|
<form class="w-full max-w-xs" on:submit={addEmail}>
|
|
|
|
<div class="mb-4">
|
|
|
|
<input
|
|
|
|
type="email"
|
|
|
|
name="new_email"
|
|
|
|
placeholder={$t('settings.new_email')}
|
|
|
|
bind:value={new_email}
|
|
|
|
id="new_email"
|
|
|
|
class="block mb-2 input input-bordered w-full max-w-xs"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div>
|
2024-12-12 19:20:58 -05:00
|
|
|
<button class="py-2 px-4 mb-4 btn btn-primary">{$t('settings.email_change')}</button>
|
2024-12-11 20:46:20 -05:00
|
|
|
</div>
|
|
|
|
</form>
|
2024-07-09 11:39:07 -04:00
|
|
|
</div>
|
2024-08-23 23:49:05 -04:00
|
|
|
|
2024-12-13 20:21:44 -05:00
|
|
|
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.mfa_page_title')}</h1>
|
2024-12-12 19:20:58 -05:00
|
|
|
|
|
|
|
<div class="flex justify-center mb-4">
|
|
|
|
<div>
|
2024-12-13 10:48:18 -05:00
|
|
|
{#if !data.props.authenticators}
|
2024-12-13 20:21:44 -05:00
|
|
|
<p>{$t('settings.mfa_not_enabled')}</p>
|
|
|
|
<button class="btn btn-primary mt-2" on:click={() => (isMFAModalOpen = true)}
|
|
|
|
>{$t('settings.enable_mfa')}</button
|
2024-12-13 10:48:18 -05:00
|
|
|
>
|
|
|
|
{:else}
|
2024-12-13 20:21:44 -05:00
|
|
|
<button class="btn btn-warning mt-2" on:click={disableMfa}
|
|
|
|
>{$t('settings.disable_mfa')}</button
|
|
|
|
>
|
2024-12-12 19:20:58 -05:00
|
|
|
{/if}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2024-11-01 20:08:23 -04:00
|
|
|
<div class="flex flex-col items-center mt-4">
|
2024-11-01 20:12:43 -04:00
|
|
|
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">
|
|
|
|
{$t('adventures.visited_region_check')}
|
|
|
|
</h1>
|
2024-08-23 18:41:59 -04:00
|
|
|
<p>
|
2024-11-01 20:12:43 -04:00
|
|
|
{$t('adventures.visited_region_check_desc')}
|
2024-08-23 18:41:59 -04:00
|
|
|
</p>
|
2024-12-11 20:46:20 -05:00
|
|
|
<p>{$t('adventures.update_visited_regions_disclaimer')}</p>
|
|
|
|
|
2024-08-23 23:49:05 -04:00
|
|
|
<button class="btn btn-neutral mt-2 mb-2" on:click={checkVisitedRegions}
|
2024-11-01 20:12:43 -04:00
|
|
|
>{$t('adventures.update_visited_regions')}</button
|
2024-08-23 18:41:59 -04:00
|
|
|
>
|
|
|
|
</div>
|
2024-08-23 23:49:05 -04:00
|
|
|
|
2024-07-08 11:44:39 -04:00
|
|
|
<small class="text-center"
|
2024-11-30 10:24:27 -05:00
|
|
|
><b>For Debug Use:</b> UUID={user.uuid} | Staff user: {user.is_staff}</small
|
2024-07-08 11:44:39 -04:00
|
|
|
>
|
|
|
|
|
|
|
|
<svelte:head>
|
|
|
|
<title>User Settings | AdventureLog</title>
|
|
|
|
<meta
|
|
|
|
name="description"
|
|
|
|
content="Update your user account settings here. Change your username, first name, last name, and profile icon."
|
|
|
|
/>
|
|
|
|
</svelte:head>
|