grouped and sorted licence categories display

This commit is contained in:
Alex
2024-10-08 07:39:03 +02:00
parent 9023979b43
commit 1367ba4fa1
3 changed files with 83 additions and 32 deletions

View File

@@ -47,7 +47,7 @@ export async function handle({ event, resolve }) {
event.locals.subscriptions = data.subscriptions; event.locals.subscriptions = data.subscriptions;
event.locals.user = data.user; event.locals.user = data.user;
event.locals.licence_categories = data.licence_categories; event.locals.licence_categories = data.licence_categories;
console.dir(event.locals.licence_categories); console.dir(event.locals.user);
if (event.locals.user.date_of_birth) { if (event.locals.user.date_of_birth) {
event.locals.user.date_of_birth = event.locals.user.date_of_birth =
event.locals.user.date_of_birth.split("T")[0]; event.locals.user.date_of_birth.split("T")[0];

View File

@@ -24,6 +24,18 @@ export const actions = {
updateUser: async ({ request, fetch, cookies, locals }) => { updateUser: async ({ request, fetch, cookies, locals }) => {
let formData = await request.formData(); let formData = await request.formData();
const licenceCategories = formData
.getAll("licence_categories[]")
.filter((value) => typeof value === "string")
.map((value) => {
try {
return JSON.parse(value);
} catch (e) {
console.error("Failed to parse licence category:", value);
return null;
}
})
.filter(Boolean);
/** @type {Partial<App.Locals['user']>} */ /** @type {Partial<App.Locals['user']>} */
const updateData = { const updateData = {
id: Number(formData.get("id")), id: Number(formData.get("id")),
@@ -67,19 +79,15 @@ export const actions = {
issued_date: toRFC3339(formData.get("issued_date")), issued_date: toRFC3339(formData.get("issued_date")),
expiration_date: toRFC3339(formData.get("expiration_date")), expiration_date: toRFC3339(formData.get("expiration_date")),
country: String(formData.get("country")), country: String(formData.get("country")),
licence_categories: formData licence_categories: licenceCategories,
.getAll("licence_categories[]")
.map((category) => ({
id: -1, // Use -1 as a placeholder for new categories
category: String(category),
})),
}, },
}; };
// Remove undefined or null properties // Remove undefined or null properties
const cleanUpdateData = Object.fromEntries( const cleanUpdateData = JSON.parse(
Object.entries(updateData).filter(([_, v]) => v != null) JSON.stringify(updateData),
(key, value) => (value !== null && value !== "" ? value : undefined)
); );
console.dir(formData);
console.dir(cleanUpdateData); console.dir(cleanUpdateData);
const apiURL = `${BASE_API_URI}/backend/users/update/`; const apiURL = `${BASE_API_URI}/backend/users/update/`;
const res = await fetch(apiURL, { const res = await fetch(apiURL, {

View File

@@ -20,9 +20,36 @@
/** @type {App.Locals['user']}*/ /** @type {App.Locals['user']}*/
$: user = $page.data.user; $: user = $page.data.user;
/**
* creates groups of categories depending on the first letter
* @param {App.Locals['licence_categories']} categories - the categories to sort and group
* @returns {Object.<string, App.Locals['licence_categories']>} Grouped categories
*/
function groupCategories(categories) {
return Object.entries(categories)
.sort((a, b) => a[1].category.localeCompare(b[1].category))
.reduce(
(
/** @type {Object.<string, App.Locals['licence_categories']>} */ acc,
[_, category]
) => {
const firstLetter = category.category[0];
if (!acc[firstLetter]) {
acc[firstLetter] = [];
}
acc[firstLetter].push(category);
return acc;
},
{}
);
}
/** @type {App.Locals['licence_categories']} */ /** @type {App.Locals['licence_categories']} */
$: licence_categories = $page.data.licence_categories; $: licence_categories = $page.data.licence_categories;
/** @type {Object.<string, App.Locals['licence_categories']>} */
$: groupedCategories = groupCategories(licence_categories);
// /** @typedef {{name: string, src: string}} Avatar */ // /** @typedef {{name: string, src: string}} Avatar */
// const avatarFiles = import.meta.glob("$lib/img/Avatar-*.jpeg", { // const avatarFiles = import.meta.glob("$lib/img/Avatar-*.jpeg", {
// eager: true, // eager: true,
@@ -368,24 +395,30 @@
<div class="licence-categories"> <div class="licence-categories">
<h3>{$t("licence_categories")}</h3> <h3>{$t("licence_categories")}</h3>
<div class="checkbox-grid"> <div class="checkbox-grid">
{#each licence_categories as category} {#each Object.entries(groupedCategories) as [group, categories], groupIndex}
<div class="checkbox-item"> {#if groupIndex > 0}
<div class="checkbox-label-container"> <div class="category-break" />
<InputField {/if}
type="checkbox" {#each categories as category}
name="licence_categories[]" <div class="checkbox-item">
value={category.category} <div class="checkbox-label-container">
label={category.category} <InputField
checked={user.drivers_licence.licence_categories != null && type="checkbox"
user.drivers_licence.licence_categories.some( name="licence_categories[]"
(cat) => cat.category === category.category value={JSON.stringify(category)}
)} label={category.category}
/> checked={user.drivers_licence.licence_categories !=
null &&
user.drivers_licence.licence_categories.some(
(cat) => cat.category === category.category
)}
/>
</div>
<span class="checkbox-description">
{$t(`licenceCategory.${category.category}`)}
</span>
</div> </div>
<span class="checkbox-description"> {/each}
{$t(`licenceCategory.${category.category}`)}
</span>
</div>
{/each} {/each}
</div> </div>
</div> </div>
@@ -525,6 +558,16 @@
{/if} {/if}
<style> <style>
.category-break {
grid-column: 1 / -1;
height: 1px;
background-color: #ccc;
margin-top: 10px;
margin-left: 20%;
width: 60%;
opacity: 0.4;
}
.licence-categories { .licence-categories {
margin-bottom: 20px; margin-bottom: 20px;
} }
@@ -532,7 +575,7 @@
.checkbox-grid { .checkbox-grid {
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 5px; gap: 0px;
} }
.checkbox-item { .checkbox-item {
@@ -543,21 +586,21 @@
.checkbox-label-container { .checkbox-label-container {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 10px; width: 4em;
margin-right: 5px;
} }
.checkbox-description { .checkbox-description {
flex: 1; flex: 1;
font-size: 14px; font-size: 15px;
color: #9b9b9b; color: #9b9b9b;
text-align: right;
margin-left: 10px; margin-left: 10px;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.checkbox-grid { .checkbox-grid {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 20px; gap: 0px;
} }
} }