add: UserEditForm

This commit is contained in:
Alex
2024-10-10 07:04:50 +02:00
parent 79ffb5051c
commit fca5af2c9a
2 changed files with 586 additions and 523 deletions

View File

@@ -0,0 +1,577 @@
<script>
import InputField from "$lib/components/InputField.svelte";
import SmallLoader from "$lib/components/SmallLoader.svelte";
import { onMount } from "svelte";
import { applyAction, enhance } from "$app/forms";
import { page } from "$app/stores";
import { receive, send } from "$lib/utils/helpers";
import { t } from "svelte-i18n";
import { fly } from "svelte/transition";
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
export let form;
/** @type {App.Locals['subscriptions']}*/
export let subscriptions;
/** @type {App.Locals['user']}*/
export let user;
/** @type {App.Locals['licence_categories']} */
export let licence_categories;
const userStatusOptions = [
{ value: 1, label: $t("userStatus.1"), color: "#b1b1b1" }, // Grey for "Nicht verifiziert"
{ value: 2, label: $t("userStatus.2"), color: "#90EE90" }, // Light green for "Verifiziert"
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
const userRoleOptions = [
{ value: 0, label: $t("userRole.0"), color: "#b1b1b1" }, // Grey for "Mitglied"
{ value: 1, label: $t("userRole.1"), color: "#00bc00" }, // Green for "Betrachter"
{ value: 4, label: $t("userRole.4"), color: "#FFC0CB" }, // Pink for "Bearbeiter"
{ value: 8, label: $t("userRole.8"), color: "#FF4646" }, // Red for "Admin"
];
const membershipStatusOptions = [
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
const licenceStatusOptions = [
{ value: 1, label: $t("userStatus.1"), color: "#b1b1b1" }, // Grey for "Nicht verifiziert"
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
const TABS = ["profile", "licence", "membership", "bankaccount"];
let activeTab = TABS[0];
let isUpdating = false,
password = "",
password2 = "";
/** @type {Object.<string, App.Locals['licence_categories']>} */
$: groupedCategories = groupCategories(licence_categories);
$: subscriptionModelOptions = subscriptions.map((sub) => ({
value: sub?.name ?? "",
label: sub?.name ?? "",
}));
$: selectedSubscriptionModel =
subscriptions.find(
(sub) => sub?.id === user.membership?.subscription_model.id
) || null;
/**
* 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;
},
{}
);
}
onMount(() => {
console.dir(user);
});
/**
* Sets the active tab
* @param {string} tab - The tab to set as active
*/
function setActiveTab(tab) {
activeTab = tab;
}
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
const handleUpdate = async ({ form, formData, action, cancel }) => {
isUpdating = true;
return async ({ result }) => {
isUpdating = false;
if (result.type === "success" || result.type === "redirect") {
close();
}
await applyAction(result);
};
};
</script>
<form
class="content"
action="?/updateUser"
method="POST"
use:enhance={handleUpdate}
>
<input name="id" type="number" hidden bind:value={user.id} />
<h1 class="step-title" style="text-align: center;">{$t("user_edit")}</h1>
{#if form?.success}
<h4
class="step-subtitle warning"
in:receive={{ key: Math.floor(Math.random() * 100) }}
out:send={{ key: Math.floor(Math.random() * 100) }}
>
Um einen fehlerhaften upload Ihres Bildes zu vermeiden, clicke bitte auf
den "Update" Button unten.
</h4>
{/if}
{#if form?.errors}
{#each form?.errors as error (error.id)}
<h4
class="step-subtitle warning"
in:receive={{ key: error.id }}
out:send={{ key: error.id }}
>
{$t(error.field) + ": " + $t(error.key)}
</h4>
{/each}
{/if}
<input
type="hidden"
hidden
name="profile_picture"
bind:value={user.profile_picture}
/>
<div class="button-container">
{#each TABS as tab}
<button
type="button"
class="button-dark"
class:active={activeTab === tab}
on:click={() => setActiveTab(tab)}
>
{$t(tab)}
</button>
{/each}
</div>
<div
class="tab-content"
style="display: {activeTab === 'profile' ? 'block' : 'none'}"
>
<InputField
name="status"
type="select"
label={$t("status")}
bind:value={user.status}
options={userStatusOptions}
/>
{#if user.role_id === 8}
<InputField
name="role_id"
type="select"
label={$t("user_role")}
bind:value={user.role_id}
options={userRoleOptions}
/>
{/if}
<InputField
name="password"
type="password"
label={$t("password")}
placeholder={$t("placeholder.password")}
bind:value={password}
otherPasswordValue={password2}
/>
<InputField
name="password2"
type="password"
label={$t("password_repeat")}
placeholder={$t("placeholder.password")}
bind:value={password2}
otherPasswordValue={password}
/>
<InputField
name="first_name"
label={$t("first_name")}
bind:value={user.first_name}
placeholder={$t("placeholder.first_name")}
required={true}
/>
<InputField
name="last_name"
label={$t("last_name")}
bind:value={user.last_name}
placeholder={$t("placeholder.last_name")}
required={true}
/>
<InputField
name="company"
label={$t("company")}
bind:value={user.company}
placeholder={$t("placeholder.company")}
/>
<InputField
name="email"
type="email"
label={$t("email")}
bind:value={user.email}
placeholder={$t("placeholder.email")}
required={true}
/>
<InputField
name="phone"
type="tel"
label={$t("phone")}
bind:value={user.phone}
placeholder={$t("placeholder.phone")}
/>
<InputField
name="birth_date"
type="date"
label={$t("birth_date")}
bind:value={user.date_of_birth}
placeholder={$t("placeholder.birth_date")}
/>
<InputField
name="address"
label={$t("address")}
bind:value={user.address}
placeholder={$t("placeholder.address")}
/>
<InputField
name="zip_code"
label={$t("zip_code")}
bind:value={user.zip_code}
placeholder={$t("placeholder.zip_code")}
/>
<InputField
name="city"
label={$t("city")}
bind:value={user.city}
placeholder={$t("placeholder.city")}
/>
<InputField
name="notes"
type="textarea"
label={$t("notes")}
bind:value={user.notes}
placeholder={$t("placeholder.notes", {
values: { name: user.first_name || "" },
})}
rows={10}
/>
</div>
<div
class="tab-content"
style="display: {activeTab === 'licence' ? 'block' : 'none'}"
>
<InputField
name="licence_status"
type="select"
label={$t("status")}
bind:value={user.drivers_licence.status}
options={licenceStatusOptions}
/>
<InputField
name="licence_number"
type="text"
label={$t("licence_number")}
bind:value={user.drivers_licence.licence_number}
placeholder={$t("placeholder.licence_number")}
toUpperCase={true}
/>
<InputField
name="issued_date"
type="date"
label={$t("issued_date")}
bind:value={user.drivers_licence.issued_date}
placeholder={$t("placeholder.issued_date")}
/>
<InputField
name="expiration_date"
type="date"
label={$t("expiration_date")}
bind:value={user.drivers_licence.expiration_date}
placeholder={$t("placeholder.expiration_date")}
/>
<InputField
name="country"
label={$t("country")}
bind:value={user.drivers_licence.country}
placeholder={$t("placeholder.issuing_country")}
/>
<div class="licence-categories">
<h3>{$t("licence_categories")}</h3>
<div class="checkbox-grid">
{#each Object.entries(groupedCategories) as [group, categories], groupIndex}
{#if groupIndex > 0}
<div class="category-break" />
{/if}
{#each categories as category}
<div class="checkbox-item">
<div class="checkbox-label-container">
<InputField
type="checkbox"
name="licence_categories[]"
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>
{/each}
{/each}
</div>
</div>
</div>
<div
class="tab-content"
style="display: {activeTab === 'membership' ? 'block' : 'none'}"
>
<InputField
name="membership_status"
type="select"
label={$t("status")}
bind:value={user.membership.status}
options={membershipStatusOptions}
/>
<InputField
name="subscription_model_name"
type="select"
label={$t("subscription_model")}
bind:value={user.membership.subscription_model.name}
options={subscriptionModelOptions}
/>
<div class="subscription-info">
<div class="subscription-column">
<p>
<strong>{$t("monthly_fee")}:</strong>
{selectedSubscriptionModel?.monthly_fee || "-"}
</p>
<p>
<strong>{$t("hourly_rate")}:</strong>
{selectedSubscriptionModel?.hourly_rate || "-"}
</p>
{#if selectedSubscriptionModel?.included_hours_per_year}
<p>
<strong>{$t("included_hours_per_year")}:</strong>
{selectedSubscriptionModel?.included_hours_per_year}
</p>
{/if}
{#if selectedSubscriptionModel?.included_hours_per_month}
<p>
<strong>{$t("included_hours_per_month")}:</strong>
{selectedSubscriptionModel?.included_hours_per_month}
</p>
{/if}
</div>
<div class="subscription-column">
<p>
<strong>{$t("details")}:</strong>
{selectedSubscriptionModel?.details || "-"}
</p>
{#if selectedSubscriptionModel?.conditions}
<p>
<strong>{$t("conditions")}:</strong>
{selectedSubscriptionModel?.conditions}
</p>
{/if}
</div>
</div>
<InputField
name="membership_start_date"
type="date"
label={$t("start")}
bind:value={user.membership.start_date}
placeholder={$t("placeholder.start_date")}
/>
<InputField
name="membership_end_date"
type="date"
label={$t("end")}
bind:value={user.membership.end_date}
placeholder={$t("placeholder.end_date")}
/>
<InputField
name="parent_member_id"
type="number"
label={$t("parent_member_id")}
bind:value={user.membership.parent_member_id}
placeholder={$t("placeholder.parent_member_id")}
/>
</div>
<div
class="tab-content"
style="display: {activeTab === 'bankaccount' ? 'block' : 'none'}"
>
<InputField
name="account_holder_name"
label={$t("bank_account_holder")}
bind:value={user.bank_account.account_holder_name}
placeholder={$t("placeholder.bank_account_holder")}
/>
<InputField
name="bank"
label={$t("bank_name")}
bind:value={user.bank_account.bank}
placeholder={$t("placeholder.bank_name")}
/>
<InputField
name="iban"
label={$t("iban")}
bind:value={user.bank_account.iban}
placeholder={$t("placeholder.iban")}
toUpperCase={true}
/>
<InputField
name="bic"
label={$t("bic")}
bind:value={user.bank_account.bic}
placeholder={$t("placeholder.bic")}
toUpperCase={true}
/>
<InputField
name="mandate_reference"
label={$t("mandate_reference")}
bind:value={user.bank_account.mandate_reference}
placeholder={$t("placeholder.mandate_reference")}
/>
<InputField
name="mandate_date_signed"
label={$t("mandate_date_signed")}
type="date"
bind:value={user.bank_account.mandate_date_signed}
readonly={true}
/>
</div>
<div class="button-container">
{#if isUpdating}
<SmallLoader width={30} message={"Aktualisiere..."} />
{:else}
<button type="button" class="button-dark" on:click={close}>
{$t("cancel")}</button
>
<button type="submit" class="button-dark">{$t("confirm")}</button>
{/if}
</div>
</form>
<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 {
margin-bottom: 20px;
}
.checkbox-grid {
display: grid;
grid-template-columns: 1fr;
gap: 0px;
}
.checkbox-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.checkbox-label-container {
flex: 0 0 auto;
width: 4em;
margin-right: 5px;
}
.checkbox-description {
flex: 1;
font-size: 15px;
color: #9b9b9b;
margin-left: 10px;
}
@media (min-width: 768px) {
.checkbox-grid {
grid-template-columns: 1fr 1fr;
gap: 0px;
}
}
@media (max-width: 480px) {
.checkbox-item {
flex-direction: column;
align-items: flex-start;
}
.checkbox-description {
margin-left: 24px;
margin-top: 5px;
text-align: left;
}
}
.subscription-info {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 1rem;
font-size: 0.9rem;
}
.subscription-column {
flex: 1;
min-width: 200px;
}
.subscription-column p {
margin: 0.5rem 0;
}
.subscription-column strong {
display: inline-block;
min-width: 100px;
}
.tab-content {
padding: 1rem;
border-radius: 0 0 3px 3px;
}
.button-container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
margin-top: 1rem;
width: 100%;
}
.button-container button {
flex: 1 1 0;
min-width: 120px;
max-width: calc(50%-5px);
}
@media (max-width: 480px) {
.button-container button {
flex-basis: 100%;
max-width: none;
}
}
</style>

View File

@@ -1,15 +1,13 @@
<script> <script>
import ImageInput from "$lib/components/ImageInput.svelte";
import InputField from "$lib/components/InputField.svelte";
import SmallLoader from "$lib/components/SmallLoader.svelte"; import SmallLoader from "$lib/components/SmallLoader.svelte";
import Modal from "$lib/components/Modal.svelte"; import Modal from "$lib/components/Modal.svelte";
import Avatar from "$lib/img/TeamAvatar.jpeg";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { applyAction, enhance } from "$app/forms"; import { applyAction, enhance } from "$app/forms";
import { page } from "$app/stores"; import { page } from "$app/stores";
import { receive, send } from "$lib/utils/helpers"; import { receive, send } from "$lib/utils/helpers";
import { t } from "svelte-i18n"; import { t } from "svelte-i18n";
import { fly } from "svelte/transition"; import { fly } from "svelte/transition";
import UserEditForm from "$lib/components/UserEditForm.svelte";
/** @type {import('./$types').ActionData} */ /** @type {import('./$types').ActionData} */
export let form; export let form;
@@ -20,83 +18,10 @@
/** @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']>} */ let showModal = false;
$: groupedCategories = groupCategories(licence_categories);
// /** @typedef {{name: string, src: string}} Avatar */
// const avatarFiles = import.meta.glob("$lib/img/Avatar-*.jpeg", {
// eager: true,
// });
// /** @type{Avatar[]} */
// let avatars = [];
const TABS = ["profile", "licence", "membership", "bankaccount"];
let activeTab = TABS[0];
$: subscriptionModelOptions = subscriptions.map((sub) => ({
value: sub?.name ?? "",
label: sub?.name ?? "",
}));
const userStatusOptions = [
{ value: 1, label: $t("userStatus.1"), color: "#b1b1b1" }, // Grey for "Nicht verifiziert"
{ value: 2, label: $t("userStatus.2"), color: "#90EE90" }, // Light green for "Verifiziert"
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
const userRoleOptions = [
{ value: 0, label: $t("userRole.0"), color: "#b1b1b1" }, // Grey for "Mitglied"
{ value: 1, label: $t("userRole.1"), color: "#00bc00" }, // Green for "Betrachter"
{ value: 4, label: $t("userRole.4"), color: "#FFC0CB" }, // Pink for "Bearbeiter"
{ value: 8, label: $t("userRole.8"), color: "#FF4646" }, // Red for "Admin"
];
const membershipStatusOptions = [
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
const licenceStatusOptions = [
{ value: 1, label: $t("userStatus.1"), color: "#b1b1b1" }, // Grey for "Nicht verifiziert"
{ value: 3, label: $t("userStatus.3"), color: "#00bc00" }, // Green for "Aktiv"
{ value: 4, label: $t("userStatus.4"), color: "#FFC0CB" }, // Pink for "Passiv"
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
];
let showModal = false,
isUploading = false,
isUpdating = false,
// showAvatars = false,
password = "",
password2 = "";
const open = () => (showModal = true); const open = () => (showModal = true);
const close = () => { const close = () => {
@@ -105,38 +30,10 @@
form.errors = undefined; form.errors = undefined;
} }
}; };
// const toggleAvatars = () => (showAvatars = !showAvatars);
$: selectedSubscriptionModel =
subscriptions.find(
(sub) => sub?.id === user.membership?.subscription_model.id
) || null;
onMount(() => { onMount(() => {
console.dir(user); console.dir(user);
}); });
/**
* Sets the active tab
* @param {string} tab - The tab to set as active
*/
function setActiveTab(tab) {
activeTab = tab;
}
/** @type {import('./$types').SubmitFunction} */
const handleUpdate = async ({ form, formData, action, cancel }) => {
isUpdating = true;
return async ({ result }) => {
isUpdating = false;
if (result.type === "success" || result.type === "redirect") {
close();
}
await applyAction(result);
};
};
/** @type {import('./$types').SubmitFunction} */
</script> </script>
<div class="hero-container"> <div class="hero-container">
@@ -202,363 +99,13 @@
{#if showModal} {#if showModal}
<Modal on:close={close}> <Modal on:close={close}>
<form <UserEditForm
class="content" {form}
action="?/updateUser" {user}
method="POST" {subscriptions}
use:enhance={handleUpdate} {licence_categories}
> on:cancel={close}
<input name="id" type="number" hidden bind:value={user.id} />
<h1 class="step-title" style="text-align: center;">{$t("user_edit")}</h1>
{#if form?.success}
<h4
class="step-subtitle warning"
in:receive={{ key: Math.floor(Math.random() * 100) }}
out:send={{ key: Math.floor(Math.random() * 100) }}
>
Um einen fehlerhaften upload Ihres Bildes zu vermeiden, clicke bitte
auf den "Update" Button unten.
</h4>
{/if}
{#if form?.errors}
{#each form?.errors as error (error.id)}
<h4
class="step-subtitle warning"
in:receive={{ key: error.id }}
out:send={{ key: error.id }}
>
{$t(error.field) + ": " + $t(error.key)}
</h4>
{/each}
{/if}
<input
type="hidden"
hidden
name="profile_picture"
bind:value={user.profile_picture}
/> />
<div class="button-container">
{#each TABS as tab}
<button
type="button"
class="button-dark"
class:active={activeTab === tab}
on:click={() => setActiveTab(tab)}
>
{$t(tab)}
</button>
{/each}
</div>
<div
class="tab-content"
style="display: {activeTab === 'profile' ? 'block' : 'none'}"
>
<InputField
name="status"
type="select"
label={$t("status")}
bind:value={user.status}
options={userStatusOptions}
/>
{#if user.role_id === 8}
<InputField
name="role_id"
type="select"
label={$t("user_role")}
bind:value={user.role_id}
options={userRoleOptions}
/>
{/if}
<InputField
name="password"
type="password"
label={$t("password")}
placeholder={$t("placeholder.password")}
bind:value={password}
otherPasswordValue={password2}
/>
<InputField
name="password2"
type="password"
label={$t("password_repeat")}
placeholder={$t("placeholder.password")}
bind:value={password2}
otherPasswordValue={password}
/>
<InputField
name="first_name"
label={$t("first_name")}
bind:value={user.first_name}
placeholder={$t("placeholder.first_name")}
required={true}
/>
<InputField
name="last_name"
label={$t("last_name")}
bind:value={user.last_name}
placeholder={$t("placeholder.last_name")}
required={true}
/>
<InputField
name="company"
label={$t("company")}
bind:value={user.company}
placeholder={$t("placeholder.company")}
/>
<InputField
name="email"
type="email"
label={$t("email")}
bind:value={user.email}
placeholder={$t("placeholder.email")}
required={true}
/>
<InputField
name="phone"
type="tel"
label={$t("phone")}
bind:value={user.phone}
placeholder={$t("placeholder.phone")}
/>
<InputField
name="birth_date"
type="date"
label={$t("birth_date")}
bind:value={user.date_of_birth}
placeholder={$t("placeholder.birth_date")}
/>
<InputField
name="address"
label={$t("address")}
bind:value={user.address}
placeholder={$t("placeholder.address")}
/>
<InputField
name="zip_code"
label={$t("zip_code")}
bind:value={user.zip_code}
placeholder={$t("placeholder.zip_code")}
/>
<InputField
name="city"
label={$t("city")}
bind:value={user.city}
placeholder={$t("placeholder.city")}
/>
<InputField
name="notes"
type="textarea"
label={$t("notes")}
bind:value={user.notes}
placeholder={$t("placeholder.notes", {
values: { name: user.first_name || "" },
})}
rows={10}
/>
</div>
<div
class="tab-content"
style="display: {activeTab === 'licence' ? 'block' : 'none'}"
>
<InputField
name="licence_status"
type="select"
label={$t("status")}
bind:value={user.drivers_licence.status}
options={licenceStatusOptions}
/>
<InputField
name="licence_number"
type="text"
label={$t("licence_number")}
bind:value={user.drivers_licence.licence_number}
placeholder={$t("placeholder.licence_number")}
toUpperCase={true}
/>
<InputField
name="issued_date"
type="date"
label={$t("issued_date")}
bind:value={user.drivers_licence.issued_date}
placeholder={$t("placeholder.issued_date")}
/>
<InputField
name="expiration_date"
type="date"
label={$t("expiration_date")}
bind:value={user.drivers_licence.expiration_date}
placeholder={$t("placeholder.expiration_date")}
/>
<InputField
name="country"
label={$t("country")}
bind:value={user.drivers_licence.country}
placeholder={$t("placeholder.issuing_country")}
/>
<div class="licence-categories">
<h3>{$t("licence_categories")}</h3>
<div class="checkbox-grid">
{#each Object.entries(groupedCategories) as [group, categories], groupIndex}
{#if groupIndex > 0}
<div class="category-break" />
{/if}
{#each categories as category}
<div class="checkbox-item">
<div class="checkbox-label-container">
<InputField
type="checkbox"
name="licence_categories[]"
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>
{/each}
{/each}
</div>
</div>
</div>
<div
class="tab-content"
style="display: {activeTab === 'membership' ? 'block' : 'none'}"
>
<InputField
name="membership_status"
type="select"
label={$t("status")}
bind:value={user.membership.status}
options={membershipStatusOptions}
/>
<InputField
name="subscription_model_name"
type="select"
label={$t("subscription_model")}
bind:value={user.membership.subscription_model.name}
options={subscriptionModelOptions}
/>
<div class="subscription-info">
<div class="subscription-column">
<p>
<strong>{$t("monthly_fee")}:</strong>
{selectedSubscriptionModel?.monthly_fee || "-"}
</p>
<p>
<strong>{$t("hourly_rate")}:</strong>
{selectedSubscriptionModel?.hourly_rate || "-"}
</p>
{#if selectedSubscriptionModel?.included_hours_per_year}
<p>
<strong>{$t("included_hours_per_year")}:</strong>
{selectedSubscriptionModel?.included_hours_per_year}
</p>
{/if}
{#if selectedSubscriptionModel?.included_hours_per_month}
<p>
<strong>{$t("included_hours_per_month")}:</strong>
{selectedSubscriptionModel?.included_hours_per_month}
</p>
{/if}
</div>
<div class="subscription-column">
<p>
<strong>{$t("details")}:</strong>
{selectedSubscriptionModel?.details || "-"}
</p>
{#if selectedSubscriptionModel?.conditions}
<p>
<strong>{$t("conditions")}:</strong>
{selectedSubscriptionModel?.conditions}
</p>
{/if}
</div>
</div>
<InputField
name="membership_start_date"
type="date"
label={$t("start")}
bind:value={user.membership.start_date}
placeholder={$t("placeholder.start_date")}
/>
<InputField
name="membership_end_date"
type="date"
label={$t("end")}
bind:value={user.membership.end_date}
placeholder={$t("placeholder.end_date")}
/>
<InputField
name="parent_member_id"
type="number"
label={$t("parent_member_id")}
bind:value={user.membership.parent_member_id}
placeholder={$t("placeholder.parent_member_id")}
/>
</div>
<div
class="tab-content"
style="display: {activeTab === 'bankaccount' ? 'block' : 'none'}"
>
<InputField
name="account_holder_name"
label={$t("bank_account_holder")}
bind:value={user.bank_account.account_holder_name}
placeholder={$t("placeholder.bank_account_holder")}
/>
<InputField
name="bank"
label={$t("bank_name")}
bind:value={user.bank_account.bank}
placeholder={$t("placeholder.bank_name")}
/>
<InputField
name="iban"
label={$t("iban")}
bind:value={user.bank_account.iban}
placeholder={$t("placeholder.iban")}
toUpperCase={true}
/>
<InputField
name="bic"
label={$t("bic")}
bind:value={user.bank_account.bic}
placeholder={$t("placeholder.bic")}
toUpperCase={true}
/>
<InputField
name="mandate_reference"
label={$t("mandate_reference")}
bind:value={user.bank_account.mandate_reference}
placeholder={$t("placeholder.mandate_reference")}
/>
<InputField
name="mandate_date_signed"
label={$t("mandate_date_signed")}
type="date"
bind:value={user.bank_account.mandate_date_signed}
readonly={true}
/>
</div>
<div class="button-container">
{#if isUpdating}
<SmallLoader width={30} message={"Aktualisiere..."} />
{:else}
<button type="button" class="button-dark" on:click={close}>
{$t("cancel")}</button
>
<button type="submit" class="button-dark">{$t("confirm")}</button>
{/if}
</div>
</form>
</Modal> </Modal>
{/if} {/if}
@@ -701,67 +248,6 @@
font-size: 1.1rem; font-size: 1.1rem;
} }
/* .avatar-container {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.avatar-form {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.current-avatar {
margin-bottom: 1rem;
}
.avatar-buttons {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
width: 100%;
max-width: 200px;
}
.avatar-buttons button {
margin-top: 1.5rem;
width: 100%;
}
.avatar-selection {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
margin-top: 1rem;
}
.avatar-option {
width: 80px;
height: 80px;
padding: 0;
border: none;
background: none;
cursor: pointer;
transition: transform 0.2s;
}
.avatar-option:hover,
.avatar-option:focus {
transform: scale(1.8);
}
.avatar-option img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
} */
.button-container { .button-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;