frontend: real world movement
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
|
||||
<div class="modal-background">
|
||||
<div
|
||||
transition:modal={{ duration: 1000 }}
|
||||
transition:modal|global={{ duration: 1000 }}
|
||||
class="modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</script>
|
||||
|
||||
{#key key}
|
||||
<div in:slide={{ duration, delay: duration }} out:slide={{ duration }}>
|
||||
<div in:slide|global={{ duration, delay: duration }} out:slide|global={{ duration }}>
|
||||
<slot />
|
||||
</div>
|
||||
{/key}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import InputField from "$lib/components/InputField.svelte";
|
||||
import SmallLoader from "$lib/components/SmallLoader.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { applyAction, enhance } from "$app/forms";
|
||||
import { receive, send } from "$lib/utils/helpers";
|
||||
import { t } from "svelte-i18n";
|
||||
@@ -11,57 +12,85 @@
|
||||
/** @type {App.Locals['subscriptions']}*/
|
||||
export let subscriptions;
|
||||
|
||||
/** @type {App.Locals['user']} */
|
||||
const blankUser = {
|
||||
id: 0,
|
||||
email: "",
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
phone: "",
|
||||
address: "",
|
||||
zip_code: "",
|
||||
city: "",
|
||||
company: "",
|
||||
date_of_birth: "",
|
||||
notes: "",
|
||||
profile_picture: "",
|
||||
payment_status: 0,
|
||||
status: 1,
|
||||
role_id: 0,
|
||||
membership: {
|
||||
id: 0,
|
||||
start_date: "",
|
||||
end_date: "",
|
||||
status: 3,
|
||||
parent_member_id: 0,
|
||||
subscription_model: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
},
|
||||
licence: {
|
||||
id: 0,
|
||||
status: 1,
|
||||
licence_number: "",
|
||||
issued_date: "",
|
||||
expiration_date: "",
|
||||
country: "",
|
||||
licence_categories: [],
|
||||
},
|
||||
bank_account: {
|
||||
id: 0,
|
||||
mandate_date_signed: "",
|
||||
bank: "",
|
||||
account_holder_name: "",
|
||||
iban: "",
|
||||
bic: "",
|
||||
mandate_reference: "",
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {App.Locals['user'] | null} */
|
||||
export let user;
|
||||
if (user == null) {
|
||||
user = {
|
||||
id: 0,
|
||||
email: "",
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
phone: "",
|
||||
address: "",
|
||||
zip_code: "",
|
||||
city: "",
|
||||
company: "",
|
||||
date_of_birth: "",
|
||||
notes: "",
|
||||
profile_picture: "",
|
||||
payment_status: 0,
|
||||
status: 1,
|
||||
role_id: 0,
|
||||
membership: {
|
||||
id: 0,
|
||||
start_date: "",
|
||||
end_date: "",
|
||||
status: 3,
|
||||
parent_member_id: 0,
|
||||
subscription_model: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
},
|
||||
licence: {
|
||||
id: 0,
|
||||
status: 1,
|
||||
licence_number: "",
|
||||
issued_date: "",
|
||||
expiration_date: "",
|
||||
country: "",
|
||||
licence_categories: [],
|
||||
},
|
||||
bank_account: {
|
||||
id: 0,
|
||||
mandate_date_signed: "",
|
||||
bank: "",
|
||||
account_holder_name: "",
|
||||
iban: "",
|
||||
bic: "",
|
||||
mandate_reference: "",
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {App.Locals['user'] } */
|
||||
let localUser;
|
||||
|
||||
$: {
|
||||
if (user !== undefined && !localUser) {
|
||||
localUser =
|
||||
user === null
|
||||
? { ...blankUser }
|
||||
: {
|
||||
...user,
|
||||
licence: user.licence || blankUser.licence,
|
||||
membership: user.membership || blankUser.membership,
|
||||
bank_account: user.bank_account || blankUser.bank_account,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$: isNewUser = user === null;
|
||||
$: isLoading = user === undefined;
|
||||
|
||||
$: {
|
||||
console.log("incomingUser:", user);
|
||||
}
|
||||
|
||||
// Add debug logging for user
|
||||
$: {
|
||||
console.log("processed user:", user);
|
||||
}
|
||||
/** @type {App.Locals['licence_categories']} */
|
||||
export let licence_categories;
|
||||
|
||||
@@ -91,6 +120,7 @@
|
||||
{ value: 5, label: $t("userStatus.5"), color: "#FF4646" }, // Red for "Deaktiviert"
|
||||
];
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const TABS = ["profile", "licence", "membership", "bankaccount"];
|
||||
let activeTab = TABS[0];
|
||||
|
||||
@@ -106,7 +136,7 @@
|
||||
}));
|
||||
$: selectedSubscriptionModel =
|
||||
subscriptions.find(
|
||||
(sub) => sub?.id === user.membership?.subscription_model.id
|
||||
(sub) => sub?.id === localUser.membership?.subscription_model.id
|
||||
) || null;
|
||||
|
||||
/**
|
||||
@@ -142,374 +172,386 @@
|
||||
}
|
||||
|
||||
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
|
||||
const handleUpdate = async ({ form, formData, action, cancel }) => {
|
||||
const handleUpdate = async ({ formData, action, cancel }) => {
|
||||
isUpdating = true;
|
||||
return async ({ result }) => {
|
||||
isUpdating = false;
|
||||
if (result.type === "success" || result.type === "redirect") {
|
||||
close();
|
||||
} else {
|
||||
document
|
||||
.querySelector(".modal .container")
|
||||
?.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}
|
||||
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)}
|
||||
{#if isLoading}
|
||||
<SmallLoader width={30} message={$t("loading.user_data")} />
|
||||
{:else if localUser}
|
||||
<form
|
||||
class="content"
|
||||
action="?/updateUser"
|
||||
method="POST"
|
||||
use:enhance={handleUpdate}
|
||||
>
|
||||
<input name="user[id]" type="hidden" bind:value={localUser.id} />
|
||||
<h1 class="step-title" style="text-align: center;">{$t("user.edit")}</h1>
|
||||
{#if form?.success}
|
||||
<h4
|
||||
class="step-subtitle warning"
|
||||
in:receive={{ key: error.id }}
|
||||
out:send={{ key: error.id }}
|
||||
in:receive|global={{ key: Math.floor(Math.random() * 100) }}
|
||||
out:send|global={{ key: Math.floor(Math.random() * 100) }}
|
||||
>
|
||||
{$t(error.field) + ": " + $t(error.key)}
|
||||
Um einen fehlerhaften upload Ihres Bildes zu vermeiden, clicke bitte auf
|
||||
den "Update" Button unten.
|
||||
</h4>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
{#if form?.errors}
|
||||
{#each form?.errors as error (error.id)}
|
||||
<h4
|
||||
class="step-subtitle warning"
|
||||
in:receive|global={{ key: error.id }}
|
||||
out:send|global={{ 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}
|
||||
<input
|
||||
type="hidden"
|
||||
hidden
|
||||
name="user[profile_picture]"
|
||||
bind:value={localUser.profile_picture}
|
||||
/>
|
||||
{#if user.role_id === 8}
|
||||
|
||||
<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="role_id"
|
||||
name="user[status]"
|
||||
type="select"
|
||||
label={$t("user.role")}
|
||||
bind:value={user.role_id}
|
||||
options={userRoleOptions}
|
||||
label={$t("status")}
|
||||
bind:value={localUser.status}
|
||||
options={userStatusOptions}
|
||||
/>
|
||||
{/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.licence.status}
|
||||
options={licenceStatusOptions}
|
||||
/>
|
||||
<InputField
|
||||
name="licence_number"
|
||||
type="text"
|
||||
label={$t("licence_number")}
|
||||
bind:value={user.licence.licence_number}
|
||||
placeholder={$t("placeholder.licence_number")}
|
||||
toUpperCase={true}
|
||||
/>
|
||||
<InputField
|
||||
name="issued_date"
|
||||
type="date"
|
||||
label={$t("issued_date")}
|
||||
bind:value={user.licence.issued_date}
|
||||
placeholder={$t("placeholder.issued_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="expiration_date"
|
||||
type="date"
|
||||
label={$t("expiration_date")}
|
||||
bind:value={user.licence.expiration_date}
|
||||
placeholder={$t("placeholder.expiration_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="country"
|
||||
label={$t("country")}
|
||||
bind:value={user.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.licence.licence_categories != null &&
|
||||
user.licence.licence_categories.some(
|
||||
(cat) => cat.category === category.category
|
||||
)}
|
||||
/>
|
||||
{#if localUser.role_id === 8}
|
||||
<InputField
|
||||
name="user[role_id]"
|
||||
type="select"
|
||||
label={$t("user.role")}
|
||||
bind:value={localUser.role_id}
|
||||
options={userRoleOptions}
|
||||
/>
|
||||
{/if}
|
||||
<InputField
|
||||
name="user[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="user[first_name]"
|
||||
label={$t("first_name")}
|
||||
bind:value={localUser.first_name}
|
||||
placeholder={$t("placeholder.first_name")}
|
||||
required={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[last_name]"
|
||||
label={$t("last_name")}
|
||||
bind:value={localUser.last_name}
|
||||
placeholder={$t("placeholder.last_name")}
|
||||
required={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[company]"
|
||||
label={$t("company")}
|
||||
bind:value={localUser.company}
|
||||
placeholder={$t("placeholder.company")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[email]"
|
||||
type="email"
|
||||
label={$t("email")}
|
||||
bind:value={localUser.email}
|
||||
placeholder={$t("placeholder.email")}
|
||||
required={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[phone]"
|
||||
type="tel"
|
||||
label={$t("phone")}
|
||||
bind:value={localUser.phone}
|
||||
placeholder={$t("placeholder.phone")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[date_of_birth]"
|
||||
type="date"
|
||||
label={$t("date_of_birth")}
|
||||
bind:value={localUser.date_of_birth}
|
||||
placeholder={$t("placeholder.date_of_birth")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[address]"
|
||||
label={$t("address")}
|
||||
bind:value={localUser.address}
|
||||
placeholder={$t("placeholder.address")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[zip_code]"
|
||||
label={$t("zip_code")}
|
||||
bind:value={localUser.zip_code}
|
||||
placeholder={$t("placeholder.zip_code")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[city]"
|
||||
label={$t("city")}
|
||||
bind:value={localUser.city}
|
||||
placeholder={$t("placeholder.city")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[notes]"
|
||||
type="textarea"
|
||||
label={$t("notes")}
|
||||
bind:value={localUser.notes}
|
||||
placeholder={$t("placeholder.notes", {
|
||||
values: { name: localUser.first_name || "" },
|
||||
})}
|
||||
rows={10}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="tab-content"
|
||||
style="display: {activeTab === 'licence' ? 'block' : 'none'}"
|
||||
>
|
||||
<InputField
|
||||
name="user[licence][status]"
|
||||
type="select"
|
||||
label={$t("status")}
|
||||
bind:value={localUser.licence.status}
|
||||
options={licenceStatusOptions}
|
||||
/>
|
||||
<InputField
|
||||
name="user[licence][number]"
|
||||
type="text"
|
||||
label={$t("licence_number")}
|
||||
bind:value={localUser.licence.licence_number}
|
||||
placeholder={$t("placeholder.licence_number")}
|
||||
toUpperCase={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[licence][issued_date]"
|
||||
type="date"
|
||||
label={$t("issued_date")}
|
||||
bind:value={localUser.licence.issued_date}
|
||||
placeholder={$t("placeholder.issued_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[licence][expiration_date]"
|
||||
type="date"
|
||||
label={$t("expiration_date")}
|
||||
bind:value={localUser.licence.expiration_date}
|
||||
placeholder={$t("placeholder.expiration_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[licence][country]"
|
||||
label={$t("country")}
|
||||
bind:value={localUser.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="user[licence][categories[]]"
|
||||
value={JSON.stringify(category)}
|
||||
label={category.category}
|
||||
checked={localUser.licence.licence_categories != null &&
|
||||
localUser.licence.licence_categories.some(
|
||||
(cat) => cat.category === category.category
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<span class="checkbox-description">
|
||||
{$t(`licenceCategory.${category.category}`)}
|
||||
</span>
|
||||
</div>
|
||||
<span class="checkbox-description">
|
||||
{$t(`licenceCategory.${category.category}`)}
|
||||
</span>
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
</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}
|
||||
<div
|
||||
class="tab-content"
|
||||
style="display: {activeTab === 'membership' ? 'block' : 'none'}"
|
||||
>
|
||||
<InputField
|
||||
name="user[membership][status]"
|
||||
type="select"
|
||||
label={$t("status")}
|
||||
bind:value={localUser.membership.status}
|
||||
options={membershipStatusOptions}
|
||||
/>
|
||||
<InputField
|
||||
name="user[membership][subscription_model][name]"
|
||||
type="select"
|
||||
label={$t("subscription_model")}
|
||||
bind:value={localUser.membership.subscription_model.name}
|
||||
options={subscriptionModelOptions}
|
||||
/>
|
||||
<div class="subscription-info">
|
||||
<div class="subscription-column">
|
||||
<p>
|
||||
<strong>{$t("included_hours_per_year")}:</strong>
|
||||
{selectedSubscriptionModel?.included_hours_per_year}
|
||||
<strong>{$t("monthly_fee")}:</strong>
|
||||
{selectedSubscriptionModel?.monthly_fee || "-"}
|
||||
</p>
|
||||
{/if}
|
||||
{#if selectedSubscriptionModel?.included_hours_per_month}
|
||||
<p>
|
||||
<strong>{$t("included_hours_per_month")}:</strong>
|
||||
{selectedSubscriptionModel?.included_hours_per_month}
|
||||
<strong>{$t("hourly_rate")}:</strong>
|
||||
{selectedSubscriptionModel?.hourly_rate || "-"}
|
||||
</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}
|
||||
{#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="user[membership][start_date]"
|
||||
type="date"
|
||||
label={$t("start")}
|
||||
bind:value={localUser.membership.start_date}
|
||||
placeholder={$t("placeholder.start_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[membership][end_date]"
|
||||
type="date"
|
||||
label={$t("end")}
|
||||
bind:value={localUser.membership.end_date}
|
||||
placeholder={$t("placeholder.end_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[membership][parent_member_id]"
|
||||
type="number"
|
||||
label={$t("parent_member_id")}
|
||||
bind:value={localUser.membership.parent_member_id}
|
||||
placeholder={$t("placeholder.parent_member_id")}
|
||||
/>
|
||||
</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>
|
||||
<div
|
||||
class="tab-content"
|
||||
style="display: {activeTab === 'bankaccount' ? 'block' : 'none'}"
|
||||
>
|
||||
<InputField
|
||||
name="user[bank_account][account_holder_name]"
|
||||
label={$t("bank_account_holder")}
|
||||
bind:value={localUser.bank_account.account_holder_name}
|
||||
placeholder={$t("placeholder.bank_account_holder")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[bank_account][bank_name]"
|
||||
label={$t("bank_name")}
|
||||
bind:value={localUser.bank_account.bank}
|
||||
placeholder={$t("placeholder.bank_name")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[bank_account][iban]"
|
||||
label={$t("iban")}
|
||||
bind:value={localUser.bank_account.iban}
|
||||
placeholder={$t("placeholder.iban")}
|
||||
toUpperCase={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[bank_account][bic]"
|
||||
label={$t("bic")}
|
||||
bind:value={localUser.bank_account.bic}
|
||||
placeholder={$t("placeholder.bic")}
|
||||
toUpperCase={true}
|
||||
/>
|
||||
<InputField
|
||||
name="user[bank_account][mandate_reference]"
|
||||
label={$t("mandate_reference")}
|
||||
bind:value={localUser.bank_account.mandate_reference}
|
||||
placeholder={$t("placeholder.mandate_reference")}
|
||||
/>
|
||||
<InputField
|
||||
name="user[bank_account][mandate_date_signed]"
|
||||
label={$t("mandate_date_signed")}
|
||||
type="date"
|
||||
bind:value={localUser.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={() => dispatch("cancel")}
|
||||
>
|
||||
{$t("cancel")}</button
|
||||
>
|
||||
<button type="submit" class="button-dark">{$t("confirm")}</button>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.category-break {
|
||||
|
||||
151
frontend/src/lib/css/bootstrap-custom.scss
vendored
Normal file
151
frontend/src/lib/css/bootstrap-custom.scss
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins";
|
||||
|
||||
// Core variables
|
||||
$theme-colors: (
|
||||
"primary": #d43aff,
|
||||
"secondary": #595b5c,
|
||||
"success": #00b7ef,
|
||||
"warning": rgb(225 29 72),
|
||||
"danger": #eb5424,
|
||||
"light": #9b9b9b,
|
||||
"dark": #2f2f2f,
|
||||
);
|
||||
|
||||
// Typography
|
||||
$font-family-base: "Quicksand", sans-serif;
|
||||
$font-family-monospace: "Roboto Mono", monospace;
|
||||
$font-size-base: 1rem;
|
||||
$line-height-base: 1.8;
|
||||
$headings-font-weight: normal;
|
||||
$headings-color: #fff;
|
||||
|
||||
// Body
|
||||
$body-bg: black;
|
||||
$body-color: #9b9b9b;
|
||||
|
||||
// Links
|
||||
$link-color: #00b7ef;
|
||||
$link-decoration: none;
|
||||
$link-hover-decoration: underline;
|
||||
|
||||
// Buttons
|
||||
$btn-padding-y: 1.125rem; // 18px
|
||||
$btn-padding-x: 1.75rem; // 28px
|
||||
$btn-font-weight: 500;
|
||||
$btn-letter-spacing: 1px;
|
||||
$btn-border-width: 1px;
|
||||
$btn-transition: all 0.3s ease-in-out;
|
||||
|
||||
// Forms
|
||||
$input-bg: #494848;
|
||||
$input-color: white;
|
||||
$input-border-color: #494848;
|
||||
$input-border-radius: 6px;
|
||||
$input-padding-y: 0.625rem; // 10px
|
||||
$input-padding-x: 0.625rem; // 10px
|
||||
$input-font-family: $font-family-monospace;
|
||||
$input-font-size: 1rem;
|
||||
$input-focus-border-color: lighten($input-border-color, 10%);
|
||||
$input-focus-box-shadow: none;
|
||||
|
||||
// Cards
|
||||
$card-bg: #2f2f2f;
|
||||
$card-border-radius: 3px;
|
||||
$card-border-width: 0;
|
||||
$card-spacer-y: 1.25rem;
|
||||
$card-spacer-x: 1.25rem;
|
||||
|
||||
// Modals
|
||||
$modal-content-bg: #2f2f2f;
|
||||
$modal-header-border-color: #595b5c;
|
||||
$modal-footer-border-color: #595b5c;
|
||||
|
||||
// Navbar
|
||||
$navbar-dark-color: #9b9b9b;
|
||||
$navbar-dark-hover-color: #fff;
|
||||
$navbar-padding-y: 1rem;
|
||||
$navbar-nav-link-padding-x: 1rem;
|
||||
|
||||
// Utilities
|
||||
$border-radius: 3px;
|
||||
$border-radius-lg: 6px;
|
||||
$box-shadow: none;
|
||||
|
||||
// Custom utility classes
|
||||
.text-uppercase {
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
// Custom button styles
|
||||
.btn {
|
||||
text-transform: uppercase;
|
||||
|
||||
&-dark {
|
||||
@include button-variant(transparent, #595b5c);
|
||||
|
||||
&:hover {
|
||||
border-color: #fff;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&-primary {
|
||||
&:hover {
|
||||
background-color: darken(#d43aff, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom input styles
|
||||
.form-control {
|
||||
&:focus {
|
||||
background-color: lighten($input-bg, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: 1200px;
|
||||
margin: 5em auto 0 auto;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 45px 0;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 2rem 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 45px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
|
||||
li strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
pre,
|
||||
code {
|
||||
display: inline;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
// Override Bootstrap's link hover behavior
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
border-bottom-color: #00b7ef;
|
||||
}
|
||||
// Import Bootstrap after variable overrides
|
||||
@import "bootstrap/scss/bootstrap";
|
||||
40
frontend/src/lib/css/styles.min.css
vendored
40
frontend/src/lib/css/styles.min.css
vendored
@@ -387,6 +387,46 @@ li strong {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
letter-spacing: 1px;
|
||||
padding: 18px 28px;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background-color: #4361ee;
|
||||
border-color: #4361ee;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn.primary:hover {
|
||||
background-color: #3651d4;
|
||||
border-color: #3651d4;
|
||||
}
|
||||
|
||||
.btn.danger {
|
||||
background-color: #dc2626;
|
||||
border-color: #dc2626;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn.danger:hover {
|
||||
background-color: #c51f1f;
|
||||
border-color: #c51f1f;
|
||||
}
|
||||
.warning {
|
||||
margin: 20px 0;
|
||||
padding: 1rem;
|
||||
|
||||
@@ -52,12 +52,12 @@ export default {
|
||||
no_auth_token: "Nicht authorisiert, fehlender oder ungültiger Auth-Token",
|
||||
jwt_parsing_error:
|
||||
"Nicht authorisiert, Auth-Token konnte nicht gelesen werden",
|
||||
unauthorized_update: "Sie sind nicht befugt dieses Update durchzuführen",
|
||||
unauthorized: "Sie sind nicht befugt diese Handlung durchzuführen",
|
||||
internal_server_error:
|
||||
"Verdammt, fehler auf unserer Seite, probieren Sie es nochmal, danach rufen Sie nach Hilfe",
|
||||
"Verdammt, Fehler auf unserer Seite, probieren Sie es nochmal, danach rufen Sie jemanden vom Verein an.",
|
||||
},
|
||||
validation: {
|
||||
no_user_id_provided: "Nutzer ID fehlt im Header",
|
||||
invalid_user_id: "Nutzer ID ungültig",
|
||||
invalid_subscription_model: "Model nicht gefunden",
|
||||
user_not_found: "{field} konnte nicht gefunden werden",
|
||||
invalid_user_data: "Nutzerdaten ungültig",
|
||||
@@ -98,6 +98,7 @@ export default {
|
||||
L: "Land-, Forstwirtschaftsfahrzeuge, Stapler max 40km/h",
|
||||
T: "Land-, Forstwirtschaftsfahrzeuge, Stapler max 60km/h",
|
||||
},
|
||||
users: "Mitglieder",
|
||||
user: {
|
||||
login: "Nutzer Anmeldung",
|
||||
edit: "Nutzer bearbeiten",
|
||||
@@ -144,7 +145,7 @@ export default {
|
||||
last_name: "Nachname",
|
||||
name: "Name",
|
||||
phone: "Telefonnummer",
|
||||
birth_date: "Geburtstag",
|
||||
date_of_birth: "Geburtstag",
|
||||
status: "Status",
|
||||
start: "Beginn",
|
||||
end: "Ende",
|
||||
@@ -154,4 +155,25 @@ export default {
|
||||
iban: "IBAN",
|
||||
bic: "BIC",
|
||||
mandate_reference: "SEPA Mandat",
|
||||
subscriptions: "Tarifmodelle",
|
||||
payments: "Zahlungen",
|
||||
add_new: "Neu",
|
||||
included_hours_per_year: "Inkludierte Stunden pro Jahr",
|
||||
included_hours_per_month: "Inkludierte Stunden pro Monat",
|
||||
|
||||
// For payments section
|
||||
payment: {
|
||||
id: "Zahlungs-Nr",
|
||||
amount: "Betrag",
|
||||
date: "Datum",
|
||||
status: "Status",
|
||||
},
|
||||
|
||||
// For subscription statuses
|
||||
subscriptionStatus: {
|
||||
pending: "Ausstehend",
|
||||
completed: "Abgeschlossen",
|
||||
failed: "Fehlgeschlagen",
|
||||
cancelled: "Storniert",
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user