add account page

This commit is contained in:
seriousm4x
2023-08-13 19:19:22 +02:00
parent 24aec5e1de
commit 6794091617
4 changed files with 224 additions and 20 deletions

View File

@@ -248,6 +248,7 @@
<p class="my-2">UpSnap can also check if given ports are open. You can define them below.</p>
<div class="form-control w-full">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each device.expand.ports as _, index}
<DeviceFormPort bind:device {index} />
{/each}

View File

@@ -48,15 +48,16 @@
'winter'
];
let activeTheme: string | null = '';
let avatar = $pocketbase.authStore.model?.avatar;
onMount(() => {
themeChange(false);
activeTheme = document.documentElement.getAttribute('data-theme');
});
$: avatar = $pocketbase.authStore?.model?.avatar
? $pocketbase.authStore?.model.avatar
: Math.floor(Math.random() * 9).toString();
$pocketbase.authStore.onChange(() => {
avatar = $pocketbase.authStore.model?.avatar;
});
});
async function logout() {
await $pocketbase.collection('devices').unsubscribe('*');
@@ -203,19 +204,24 @@
<img src="{backendUrl}_/images/avatars/avatar{avatar}.svg" alt="Profile pic" />
</div>
</label>
<ul
tabindex="-1"
<div
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-300 rounded-box w-40"
>
<li>
<a class="justify-between" href="/account">Edit profile</a>
</li>
<li>
<div on:click={async () => logout()} on:keydown={async () => logout()} role="none">
Logout
</div>
</li>
</ul>
<p class="font-bold">
{$isAdmin ? $pocketbase.authStore.model.email : $pocketbase.authStore.model.username}
</p>
<ul tabindex="-1" class="">
<li>
<a href="/account">Edit account</a>
</li>
<li>
<div on:click={async () => logout()} on:keydown={async () => logout()} role="none">
Logout
</div>
</li>
</ul>
</div>
</div>
{/if}
</div>

View File

@@ -28,7 +28,7 @@
permission.set(data as Permission);
})
.catch(() => {
toast.error('No permissons set for user. Ask your admin to grant you permissions.');
return;
});
$pocketbase.collection('permissions').subscribe('*', (event) => {
@@ -64,9 +64,17 @@
}
if ($pocketbase.authStore.model?.collectionName === 'users') {
await $pocketbase.collection('users').authRefresh();
await $pocketbase
.collection('users')
.authRefresh()
.catch(() => {
goto('/login');
});
} else {
await $pocketbase.admins.authRefresh();
await $pocketbase.admins.authRefresh().catch(() => {
$pocketbase.authStore.clear();
goto('/login');
});
}
});
</script>

View File

@@ -1,5 +1,194 @@
<script lang="ts">
import { pocketbase } from '$lib/stores/pocketbase';
import { goto } from '$app/navigation';
import { isAdmin, pocketbase } from '$lib/stores/pocketbase';
import { backendUrl } from '$lib/stores/pocketbase';
import toast from 'svelte-french-toast';
import Fa from 'svelte-fa';
import { faSave } from '@fortawesome/free-solid-svg-icons';
let newAvatar: number;
let newPassword = {
old: '',
password: '',
confirm: ''
};
$: adminBody = JSON.stringify({
password: newPassword.password,
passwordConfirm: newPassword.confirm
});
$: userBody = JSON.stringify({
oldPassword: newPassword.old,
password: newPassword.password,
passwordConfirm: newPassword.confirm
});
function changeAvatar() {
if ($isAdmin) {
$pocketbase.admins
.authRefresh()
.then((data) => {
data.admin.avatar = newAvatar;
$pocketbase.authStore.save(data.token, data.admin);
toast.success('Avatar saved.');
})
.catch((err) => {
toast.error(err.message);
});
} else {
$pocketbase
.collection('users')
.authRefresh()
.then((data) => {
data.record.avatar = newAvatar;
$pocketbase.authStore.save(data.token, data.record);
toast.success('Avatar saved.');
})
.catch((err) => {
toast.error(err.message);
});
}
}
function changePassword() {
fetch(
`${backendUrl}api/${$isAdmin ? 'admins' : `collections/users/records`}/${
$pocketbase.authStore.model?.id
}`,
{
method: 'PATCH',
headers: {
Authorization: $pocketbase.authStore.token,
'Content-Type': 'application/json'
},
body: $isAdmin ? adminBody : userBody
}
)
.then(async (data) => {
if (data.ok) {
toast.success('Password changed. Please login again.');
$pocketbase.authStore.clear();
goto('/login');
} else {
const j = await data.json();
if (j?.data?.password?.message) {
toast.error(j?.data?.password?.message);
} else if (j?.data?.passwordConfirm?.message) {
toast.error("Passwords don't match.");
} else if (j.data?.oldPassword?.message) {
toast.error(j.data.oldPassword.message);
} else {
toast.error(j.message || data.statusText);
}
}
})
.catch((err) => {
toast.error(err.message);
});
}
</script>
{$pocketbase.authStore.model?.email || $pocketbase.authStore.model?.username}
<h1 class="text-3xl font-bold mb-8">Account</h1>
<div class="card w-full bg-base-300 shadow-xl">
<div class="card-body">
<div class="flex flex-row gap-4 items-center">
<div class="avatar">
<div class="w-16 rounded-full">
<img
src="{backendUrl}_/images/avatars/avatar{newAvatar ??
$pocketbase.authStore.model?.avatar}.svg"
alt="Avatar {newAvatar ?? $pocketbase.authStore.model?.avatar}"
/>
</div>
</div>
<div>
<h2 class="card-title">
{$isAdmin ? $pocketbase.authStore.model?.email : $pocketbase.authStore.model?.username}
</h2>
<h3>{$isAdmin ? 'Admin' : 'User'}</h3>
</div>
</div>
<h2 class="card-title mt-4">Avatar</h2>
<form on:submit|preventDefault={changeAvatar}>
<div class="flex flex-row flex-wrap gap-4">
{#each [...Array(10).keys()] as i}
<div class="avatar btn btn-ghost btn-circle">
<div
class="w-11 rounded-full"
class:ring={newAvatar !== undefined
? i === newAvatar
: i === $pocketbase.authStore.model?.avatar}
class:ring-primary={newAvatar !== undefined
? i === newAvatar
: i === $pocketbase.authStore.model?.avatar}
class:ring-offset-base-100={newAvatar !== undefined
? i === newAvatar
: i === $pocketbase.authStore.model?.avatar}
class:ring-offset-2={newAvatar !== undefined
? i === newAvatar
: i === $pocketbase.authStore.model?.avatar}
on:click={() => (newAvatar = i)}
role="none"
>
<img src="{backendUrl}_/images/avatars/avatar{i}.svg" alt="Avatar {i}" />
</div>
</div>
{/each}
</div>
<button type="submit" class="btn btn-success mt-2"><Fa icon={faSave} />Save</button>
</form>
</div>
</div>
<div class="card w-full bg-base-300 shadow-xl mt-6">
<div class="card-body">
<h2 class="card-title">Change password</h2>
<p>After the password has been changed, you will need to log in again.</p>
<form on:submit|preventDefault={changePassword}>
<div class="form-control w-full max-w-xs">
{#if !$isAdmin}
<label class="label" for="password-old">
<span class="label-text">Old password</span>
</label>
<input
id="password-old"
type="password"
placeholder="Old password"
class="input input-bordered w-full max-w-xs"
minlength="5"
maxlength="72"
bind:value={newPassword.old}
required
/>
{/if}
<label class="label" for="password-new">
<span class="label-text">New password</span>
</label>
<input
id="password-new"
type="password"
placeholder="New password"
class="input input-bordered w-full max-w-xs"
minlength={$isAdmin ? 10 : 5}
maxlength="72"
bind:value={newPassword.password}
required
/>
</div>
<div class="form-control w-full max-w-xs">
<label class="label" for="password-confirm">
<span class="label-text">Confirm password</span>
</label>
<input
id="password-confirm"
type="password"
placeholder="New password"
class="input input-bordered w-full max-w-xs"
minlength={$isAdmin ? 10 : 5}
maxlength="72"
bind:value={newPassword.confirm}
required
/>
</div>
<button type="submit" class="btn btn-success mt-2"><Fa icon={faSave} />Save</button>
</form>
</div>
</div>