mirror of
https://github.com/seriousm4x/UpSnap.git
synced 2026-07-29 17:02:56 -04:00
add account page
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user