Files
FBLA25/src/routes/admin/users/[user]/edit/+page.svelte
T
jenkins cbe002f4c4
ci / docker_image (push) Successful in 2m28s
ci / deploy (push) Successful in 24s
Fixes
2025-06-19 17:14:18 -05:00

432 lines
12 KiB
Svelte

<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="newPassword"]');
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">
Edit User {data.user.username}{data.user.fullName ? ` (${data.user.fullName})` : ''}
</div>
</div>
<form autocomplete="off" class="px-4" method="POST" use:enhance>
<div class="mt-4 text-sm font-semibold">
Username <span class="text-red-500">*</span>
<input
class="w-full rounded font-normal"
id="username"
name="username"
placeholder="Username"
required
type="text"
value={data.user?.username}
/>
</div>
<div class="relative pt-4 text-sm font-semibold">
New password (optional)
<input
class="w-full rounded font-normal"
id="newPassword"
name="newPassword"
placeholder="New password"
type="password"
/>
<button
class="absolute right-2.5 -translate-y-1/2 transform pt-12"
onclick={showPassword}
type="button"
>
<span class="material-symbols-outlined"
>{passwordVisible ? 'visibility' : 'visibility_off'}</span
>
</button>
</div>
<div class="mt-4 text-sm font-semibold">
Full name <span class="danger-color">*</span>
<input
class="w-full rounded font-normal"
id="fullName"
name="fullName"
placeholder="Full name"
required
type="text"
value={data.user?.fullName}
/>
</div>
<div class="mt-4 text-sm font-semibold">
Email <span class="danger-color">*</span>
<input
class="w-full rounded font-normal"
id="email"
name="email"
placeholder="Email"
required
type="email"
value={data.user?.email}
/>
</div>
<div class="mt-4 text-sm font-semibold">
Phone (optional)
<input
class="w-full rounded font-normal"
id="phone"
name="phone"
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
placeholder="Phone"
type="tel"
value={data.user?.phone}
/>
</div>
<div class="mt-4 text-sm font-semibold">
Company code (optional)
<input
class="w-full rounded font-normal"
id="companyCode"
name="companyCode"
placeholder="Company code"
type="text"
value={data.user?.companyCode}
/>
</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
checked={(perms & userPerms) === userPerms}
class="select-all"
id="userPerms"
indeterminate={(perms & userPerms) !== userPerms && (perms & userPerms) > 0}
name="userPerms"
type="checkbox"
/></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 class="flex place-items-center" for="view">
<input
checked={(perms & PERMISSIONS.VIEW) > 0}
class="permCheckbox mx-1"
id="view"
name="view"
type="checkbox"
/>
<span class="ml-2">View access</span></label
>
</div>
<div class="mb-1">
<label class="flex place-items-center" for="apply">
<input
checked={(perms & PERMISSIONS.APPLY_FOR_JOBS) > 0}
class="permCheckbox mx-1"
id="apply"
name="apply"
type="checkbox"
/>
<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
checked={(perms & employerPerms) === employerPerms}
class="select-all"
id="companyPerms"
indeterminate={(perms & employerPerms) !== employerPerms &&
(perms & employerPerms) > 0}
name="companyPerms"
type="checkbox"
/></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 class="flex place-items-center" for="submitPostings">
<input
checked={(perms & PERMISSIONS.SUBMIT_POSTINGS) >= 0}
class="permCheckbox mx-1"
id="submitPostings"
name="submitPostings"
type="checkbox"
/>
<span class="ml-2">Submit postings</span></label
>
</div>
<div class="mb-1">
<label class="flex place-items-center" for="manageEmployers">
<input
checked={(perms & PERMISSIONS.MANAGE_EMPLOYERS) > 0}
class="permCheckbox mx-1"
id="manageEmployers"
name="manageEmployers"
type="checkbox"
/>
<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
checked={(perms & adminPerms) === adminPerms}
class="select-all"
id="adminPerms"
indeterminate={(perms & adminPerms) !== adminPerms && (perms & adminPerms) > 0}
name="adminPerms"
type="checkbox"
/></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 class="flex place-items-center" for="manageTags">
<input
checked={(perms & PERMISSIONS.MANAGE_TAGS) > 0}
class="permCheckbox mx-1"
id="manageTags"
name="manageTags"
type="checkbox"
/>
<span class="ml-2">Manage tags</span></label
>
</div>
<div class="mb-1">
<label class="flex place-items-center" for="managePostings">
<input
checked={(perms & PERMISSIONS.MANAGE_POSTINGS) > 0}
class="permCheckbox mx-1"
id="managePostings"
name="managePostings"
type="checkbox"
/>
<span class="ml-2">Manage postings</span></label
>
</div>
<div class="mb-1">
<label class="flex place-items-center" for="manageUsers">
<input
checked={(perms & PERMISSIONS.MANAGE_USERS) > 0}
class="permCheckbox mx-1"
id="manageUsers"
name="manageUsers"
type="checkbox"
/>
<span class="ml-2">Manage users</span></label
>
</div>
<div class="mb-1">
<label class="flex place-items-center" for="manageCompanies">
<input
checked={(perms & PERMISSIONS.MANAGE_COMPANIES) > 0}
class="permCheckbox mx-1"
id="manageCompanies"
name="manageCompanies"
type="checkbox"
/>
<span class="ml-2">Manage companies</span></label
>
</div>
</div>
</div>
</div>
<label class="flex place-items-center p-2" for="accountActive">
<input
checked={data.user?.active}
class="permCheckbox mx-1"
id="accountActive"
name="accountActive"
type="checkbox"
/>
<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"
formaction="?/submit"
type="submit"
>Save user
</button>
<button
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
onclick={openConfirm}
type="button"
>Delete user
</button>
</div>
</form>
<form class="modal" id="deleteConfirmModal" 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} type="button"
>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
class="w-full rounded font-normal"
id="confirm"
name="confirm"
pattern="I understand"
placeholder="I understand"
required
type="text"
/>
<div class="mt-4 flex justify-between">
<button class="danger-bg-color rounded px-2 py-1" formaction="?/delete" type="submit"
>Delete user
</button>
<button
class="separator-borders bg-color rounded px-2 py-1"
onclick={closeConfirm}
type="button"
>Cancel
</button>
</div>
</div>
</form>
</div>
</div>