dev
ci / docker_image (push) Successful in 1m32s
ci / deploy (push) Successful in 16s

This commit is contained in:
2025-01-26 19:12:15 -06:00
parent 76c2680c60
commit be83b7570d
43 changed files with 3202 additions and 1022 deletions
@@ -0,0 +1,420 @@
<script lang="ts">
import { onMount } from 'svelte';
import { enhance } from '$app/forms';
import type { PageProps } from './$types';
import { PERMISSIONS } from '$lib/consts';
import { userPerms, employerPerms, adminPerms, telFormatter } from '$lib/shared.svelte';
let permsAccordions: boolean[] = [false, false, false];
let passwordVisible = $state(false);
function showPassword() {
const password = document.querySelector('input[name="password"]');
if (password) {
if (password.getAttribute('type') === 'password') {
password.setAttribute('type', 'text');
passwordVisible = true;
} else {
password.setAttribute('type', 'password');
passwordVisible = false;
}
}
}
onMount(() => {
let acc = document.getElementsByClassName('accordion');
for (let i = 0; i < acc.length; i++) {
acc[i].addEventListener('click', function (this: HTMLElement, event: Event) {
const target = event?.target as HTMLElement | null;
if (target?.tagName === 'INPUT' && (target as HTMLInputElement).type === 'checkbox') {
return; // Do nothing if it's the checkbox
}
this.classList.toggle('active');
permsAccordions[i] = !permsAccordions[i];
let panel = this.nextElementSibling as HTMLElement;
if (panel.style.display === 'block') {
panel.style.display = 'none';
} else {
panel.style.display = 'block';
}
});
let selectAllCheckbox = acc[i].querySelector('.select-all') as HTMLInputElement;
selectAllCheckbox.addEventListener('change', function () {
let checkboxes =
this.parentElement!.parentElement!.parentElement!.nextElementSibling!.querySelectorAll(
'.permCheckbox'
) as NodeListOf<HTMLInputElement>;
checkboxes.forEach((checkbox) => {
checkbox.checked = selectAllCheckbox.checked;
});
});
let permCheckboxes = acc[i].nextElementSibling!.querySelectorAll(
'.permCheckbox'
) as NodeListOf<HTMLInputElement>;
permCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('change', function () {
let allChecked = true;
let someChecked = false;
permCheckboxes.forEach((cb) => {
if (cb.checked) {
someChecked = true;
} else {
allChecked = false;
}
});
selectAllCheckbox.checked = allChecked;
selectAllCheckbox.indeterminate = !allChecked && someChecked;
});
});
}
const modal: HTMLElement = document.getElementById('deleteConfirmModal') as HTMLElement;
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = 'none';
}
};
document.getElementById('phone')?.addEventListener('input', function (this: HTMLInputElement) {
this.value = telFormatter(this.value);
});
});
function openConfirm() {
document.getElementById('deleteConfirmModal')!.style.display = 'block';
}
function closeConfirm() {
document.getElementById('deleteConfirmModal')!.style.display = 'none';
}
let { data, form }: PageProps = $props();
let perms = data.user!.perms;
</script>
<div class="content">
<div class="elevated separator-borders m-4 rounded">
<div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold">Update User</div>
</div>
<form method="POST" class="px-4" autocomplete="off" use:enhance>
<div class="mt-4 text-sm font-semibold">
Username <span class="text-red-500">*</span>
<input
type="text"
name="username"
id="username"
value={data.user?.username}
placeholder="Username"
class="w-full rounded font-normal"
/>
</div>
<div class="relative pt-4 text-sm font-semibold">
Password
<input
type="password"
name="password"
id="password"
placeholder="New password"
class="w-full rounded font-normal"
/>
<button
type="button"
onclick={showPassword}
class="absolute right-2.5 -translate-y-1/2 transform pt-12"
>
<span class="material-symbols-outlined"
>{passwordVisible ? 'visibility' : 'visibility_off'}</span
>
</button>
</div>
<div class="mt-4 text-sm font-semibold">
Email (optional)
<input
type="email"
name="email"
id="email"
value={data.user?.email}
placeholder="Email"
class="w-full rounded font-normal"
/>
</div>
<div class="mt-4 text-sm font-semibold">
Phone (optional)
<input
type="tel"
name="phone"
id="phone"
value={data.user?.phone}
placeholder="Phone"
class="w-full rounded font-normal"
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
/>
</div>
<div class="mt-4 text-sm font-semibold">
Full name (optional)
<input
type="text"
name="fullName"
id="fullName"
value={data.user?.fullName}
placeholder="Full name"
class="w-full rounded font-normal"
/>
</div>
<div class="mt-4 text-sm font-semibold">
Company code (optional)
<input
type="text"
name="companyCode"
id="companyCode"
placeholder="Company code"
value={data.user?.companyCode}
class="w-full rounded font-normal"
/>
</div>
<p class="low-emphasis-text">
This code can be used to associate an employer with their company. If left blank, they will
not be able to create any postings.
</p>
<div class="bg-color separator-borders mb-2 mt-4 rounded">
<button
class="accordion flex w-full place-content-between rounded p-2 text-left"
type="button"
>
<span class="flex place-items-center">
<span class="ml-1 mr-3"
><input
type="checkbox"
name="userPerms"
id="userPerms"
class="select-all"
checked={(perms & userPerms) === userPerms}
indeterminate={(perms & userPerms) !== userPerms && (perms & userPerms) !== 0}
/></span
>User Permissions
</span>
<span class="material-symbols-outlined"
>{permsAccordions[0] ? 'arrow_drop_up' : 'arrow_drop_down'}</span
>
</button>
<div class="panel hidden p-2">
<div>
<div class="mb-1">
<label for="view" class="flex place-items-center">
<input
type="checkbox"
name="view"
id="view"
class="permCheckbox mx-1"
checked={(perms & PERMISSIONS.VIEW) !== 0}
/>
<span class="ml-2">View access</span></label
>
</div>
<div class="mb-1">
<label for="apply" class="flex place-items-center">
<input
type="checkbox"
name="apply"
id="apply"
class="permCheckbox mx-1"
checked={(perms & PERMISSIONS.APPLY_FOR_JOBS) !== 0}
/>
<span class="ml-2">Apply for jobs</span></label
>
</div>
</div>
</div>
</div>
<div class="bg-color separator-borders my-2 rounded">
<button
class="accordion flex w-full place-content-between rounded p-2 text-left"
type="button"
>
<span class="flex place-items-center">
<span class="ml-1 mr-3"
><input
type="checkbox"
name="companyPerms"
id="companyPerms"
class="select-all"
checked={(perms & employerPerms) === employerPerms}
indeterminate={(perms & employerPerms) !== employerPerms &&
(perms & employerPerms) !== 0}
/></span
>Company Permissions
</span>
<span class="material-symbols-outlined"
>{permsAccordions[1] ? 'arrow_drop_up' : 'arrow_drop_down'}</span
>
</button>
<div class="panel hidden p-2">
<div>
<div class="mb-1">
<label for="submitPostings" class="flex place-items-center">
<input
type="checkbox"
name="submitPostings"
id="submitPostings"
checked={(perms & PERMISSIONS.SUBMIT_POSTINGS) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Submit postings</span></label
>
</div>
<div class="mb-1">
<label for="manageEmployers" class="flex place-items-center">
<input
type="checkbox"
name="manageEmployers"
id="manageEmployers"
checked={(perms & PERMISSIONS.MANAGE_EMPLOYERS) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Manage employers (within their company)</span></label
>
</div>
</div>
</div>
</div>
<div class="bg-color separator-borders mt-2 rounded">
<button
class="accordion flex w-full place-content-between rounded p-2 text-left"
type="button"
>
<span class="flex place-items-center">
<span class="ml-1 mr-3"
><input
type="checkbox"
name="adminPerms"
id="adminPerms"
class="select-all"
checked={(perms & adminPerms) === adminPerms}
indeterminate={(perms & adminPerms) !== adminPerms && (perms & adminPerms) !== 0}
/></span
>Admin Permissions
</span>
<span class="material-symbols-outlined"
>{permsAccordions[0] ? 'arrow_drop_up' : 'arrow_drop_down'}</span
>
</button>
<div class="panel hidden p-2">
<div>
<div class="mb-1">
<label for="manageTags" class="flex place-items-center">
<input
type="checkbox"
name="manageTags"
id="manageTags"
checked={(perms & PERMISSIONS.MANAGE_TAGS) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Manage tags</span></label
>
</div>
<div class="mb-1">
<label for="managePostings" class="flex place-items-center">
<input
type="checkbox"
name="managePostings"
id="managePostings"
checked={(perms & PERMISSIONS.MANAGE_POSTINGS) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Manage postings</span></label
>
</div>
<div class="mb-1">
<label for="manageUsers" class="flex place-items-center">
<input
type="checkbox"
name="manageUsers"
id="manageUsers"
checked={(perms & PERMISSIONS.MANAGE_USERS) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Manage users</span></label
>
</div>
<div class="mb-1">
<label for="manageCompanies" class="flex place-items-center">
<input
type="checkbox"
name="manageCompanies"
id="manageCompanies"
checked={(perms & PERMISSIONS.MANAGE_COMPANIES) !== 0}
class="permCheckbox mx-1"
/>
<span class="ml-2">Manage companies</span></label
>
</div>
</div>
</div>
</div>
<label for="accountActive" class="flex place-items-center p-2">
<input
type="checkbox"
name="accountActive"
id="accountActive"
checked={data.user?.active}
class="permCheckbox mx-1"
/>
<span class="ml-2">Account active</span></label
>
{#if form?.errorMessage}
<div class="mb-2 text-red-500">{form.errorMessage}</div>
{/if}
<div class="flex justify-between">
<button
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
type="submit"
formaction="?/submit">Update user</button
>
<button
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
type="button"
onclick={openConfirm}>Delete user</button
>
</div>
</form>
<form id="deleteConfirmModal" class="modal" method="POST" use:enhance>
<div class="modal-content">
<div class="mb-2 inline-flex w-full justify-between">
<h2 class="font-semibold">Are you sure?</h2>
<button class="material-symbols-outlined" onclick={closeConfirm}>close</button>
</div>
<p>
This will permanently delete user <span class="font-semibold">{data.user?.username}.</span
>
</p>
<p>Please type "I understand" into the box below to confirm</p>
<input
type="text"
name="confirm"
id="confirm"
placeholder="I understand"
class="w-full rounded font-normal"
pattern="I understand"
required
/>
<div class="mt-4 flex justify-between">
<button class="danger-bg-color rounded px-2 py-1" type="submit" formaction="?/delete"
>Delete user</button
>
<button
class="separator-borders bg-color rounded px-2 py-1"
type="button"
onclick={closeConfirm}>Cancel</button
>
</div>
</div>
</form>
</div>
</div>