frontend: add defaultUser, supporter

This commit is contained in:
Alex
2025-03-02 23:12:10 +01:00
parent 29f405385e
commit 1f61c9ad71
6 changed files with 186 additions and 129 deletions

View File

@@ -80,6 +80,10 @@ declare global {
interface Types { interface Types {
licenceCategory: LicenceCategory; licenceCategory: LicenceCategory;
subscription: Subscription; subscription: Subscription;
membership: Membership;
licence: Licence;
licenceCategory: LicenceCategory;
bankAccount: BankAccount;
} }
// interface PageData {} // interface PageData {}
// interface Platform {} // interface Platform {}

View File

@@ -130,6 +130,9 @@
{#if error} {#if error}
<span class="error-message">{error}</span> <span class="error-message">{error}</span>
{/if} {/if}
{#if readonly}
<input {name} type="hidden" bind:value />
{/if}
{#if type === 'select'} {#if type === 'select'}
<select <select
{name} {name}

View File

@@ -14,85 +14,13 @@
export let subscriptions; export let subscriptions;
/** @type {App.Locals['user']} */ /** @type {App.Locals['user']} */
const blankUser = {
id: 0,
email: '',
first_name: '',
last_name: '',
password: '',
phone: '',
address: '',
zip_code: '',
city: '',
company: '',
dateofbirth: '',
notes: '',
profile_picture: '',
payment_status: 0,
status: 1,
role_id: 1,
membership: {
id: 0,
start_date: '',
end_date: '',
status: 3,
parent_member_id: 0,
subscription_model: {
id: 0,
name: '',
details: '',
conditions: '',
monthly_fee: 0,
hourly_rate: 0,
included_hours_per_month: 0,
included_hours_per_year: 0
}
},
licence: {
id: 0,
status: 1,
number: '',
issued_date: '',
expiration_date: '',
country: '',
categories: []
},
bank_account: {
id: 0,
mandate_date_signed: '',
bank: '',
account_holder_name: '',
iban: '',
bic: '',
mandate_reference: ''
}
};
/** @type {App.Locals['user'] | null} */
export let user; export let user;
/** @type {App.Locals['user']} */ /** @type {App.Locals['user']} */
export let editor; export let editor;
/** @type {App.Locals['user'] } */
let localUser;
let readonlyUser = !hasPrivilige(editor, PERMISSIONS.Update); let readonlyUser = !hasPrivilige(editor, PERMISSIONS.Update);
$: {
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; // $: isNewUser = user === null;
$: isLoading = user === undefined; $: isLoading = user === undefined;
@@ -126,7 +54,9 @@
]; ];
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const TABS = ['profile', 'licence', 'membership', 'bankaccount']; const TABS = hasPrivilige(user, PERMISSIONS.Member)
? ['profile', 'licence', 'membership', 'bankaccount']
: ['profile', 'bankaccount', 'membership'];
let activeTab = TABS[0]; let activeTab = TABS[0];
let isUpdating = false, let isUpdating = false,
@@ -140,8 +70,7 @@
label: sub?.name ?? '' label: sub?.name ?? ''
})); }));
$: selectedSubscriptionModel = $: selectedSubscriptionModel =
subscriptions.find((sub) => sub?.name === localUser.membership?.subscription_model.name) || subscriptions.find((sub) => sub?.name === user.membership?.subscription_model.name) || null;
null;
/** /**
* creates groups of categories depending on the first letter * creates groups of categories depending on the first letter
@@ -189,11 +118,11 @@
{#if isLoading} {#if isLoading}
<SmallLoader width={30} message={$t('loading.user_data')} /> <SmallLoader width={30} message={$t('loading.user_data')} />
{:else if localUser} {:else if user}
<form class="content" action="?/updateUser" method="POST" use:enhance={handleUpdate}> <form class="content" action="?/updateUser" method="POST" use:enhance={handleUpdate}>
<input name="user[id]" type="hidden" bind:value={localUser.id} /> <input name="user[id]" type="hidden" bind:value={user.id} />
<h1 class="step-title" style="text-align: center;"> <h1 class="step-title" style="text-align: center;">
{localUser.id ? $t('user.edit') : $t('user.create')} {user.id ? $t('user.edit') : $t('user.create')}
</h1> </h1>
{#if form?.success} {#if form?.success}
<h4 <h4
@@ -234,7 +163,7 @@
name="user[status]" name="user[status]"
type="select" type="select"
label={$t('status')} label={$t('status')}
bind:value={localUser.status} bind:value={user.status}
options={userStatusOptions} options={userStatusOptions}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -243,11 +172,11 @@
name="user[role_id]" name="user[role_id]"
type="select" type="select"
label={$t('user.role')} label={$t('user.role')}
bind:value={localUser.role_id} bind:value={user.role_id}
options={userRoleOptions} options={userRoleOptions}
/> />
{/if} {/if}
{#if hasPrivilige(localUser, PERMISSIONS.Member)} {#if hasPrivilige(user, PERMISSIONS.Member)}
<InputField <InputField
name="user[password]" name="user[password]"
type="password" type="password"
@@ -268,7 +197,7 @@
<InputField <InputField
name="user[first_name]" name="user[first_name]"
label={$t('user.first_name')} label={$t('user.first_name')}
bind:value={localUser.first_name} bind:value={user.first_name}
placeholder={$t('placeholder.first_name')} placeholder={$t('placeholder.first_name')}
required={true} required={true}
readonly={readonlyUser} readonly={readonlyUser}
@@ -276,7 +205,7 @@
<InputField <InputField
name="user[last_name]" name="user[last_name]"
label={$t('user.last_name')} label={$t('user.last_name')}
bind:value={localUser.last_name} bind:value={user.last_name}
placeholder={$t('placeholder.last_name')} placeholder={$t('placeholder.last_name')}
required={true} required={true}
readonly={readonlyUser} readonly={readonlyUser}
@@ -284,14 +213,14 @@
<InputField <InputField
name="user[company]" name="user[company]"
label={$t('company')} label={$t('company')}
bind:value={localUser.company} bind:value={user.company}
placeholder={$t('placeholder.company')} placeholder={$t('placeholder.company')}
/> />
<InputField <InputField
name="user[email]" name="user[email]"
type="email" type="email"
label={$t('user.email')} label={$t('user.email')}
bind:value={localUser.email} bind:value={user.email}
placeholder={$t('placeholder.email')} placeholder={$t('placeholder.email')}
required={true} required={true}
/> />
@@ -299,35 +228,39 @@
name="user[phone]" name="user[phone]"
type="tel" type="tel"
label={$t('user.phone')} label={$t('user.phone')}
bind:value={localUser.phone} bind:value={user.phone}
placeholder={$t('placeholder.phone')} placeholder={$t('placeholder.phone')}
/> />
{#if hasPrivilige(localUser, PERMISSIONS.Member)} {#if hasPrivilige(user, PERMISSIONS.Member)}
<InputField <InputField
name="user[dateofbirth]" name="user[dateofbirth]"
type="date" type="date"
label={$t('user.dateofbirth')} label={$t('user.dateofbirth')}
bind:value={localUser.dateofbirth} bind:value={user.dateofbirth}
placeholder={$t('placeholder.dateofbirth')} placeholder={$t('placeholder.dateofbirth')}
required={true}
readonly={readonlyUser} readonly={readonlyUser}
/> />
{/if} {/if}
<InputField <InputField
name="user[address]" name="user[address]"
label={$t('address')} label={$t('address')}
bind:value={localUser.address} bind:value={user.address}
required={true}
placeholder={$t('placeholder.address')} placeholder={$t('placeholder.address')}
/> />
<InputField <InputField
name="user[zip_code]" name="user[zip_code]"
label={$t('zip_code')} label={$t('zip_code')}
bind:value={localUser.zip_code} bind:value={user.zip_code}
required={true}
placeholder={$t('placeholder.zip_code')} placeholder={$t('placeholder.zip_code')}
/> />
<InputField <InputField
name="user[city]" name="user[city]"
label={$t('city')} label={$t('city')}
bind:value={localUser.city} bind:value={user.city}
required={true}
placeholder={$t('placeholder.city')} placeholder={$t('placeholder.city')}
/> />
{#if !readonlyUser} {#if !readonlyUser}
@@ -335,22 +268,22 @@
name="user[notes]" name="user[notes]"
type="textarea" type="textarea"
label={$t('notes')} label={$t('notes')}
bind:value={localUser.notes} bind:value={user.notes}
placeholder={$t('placeholder.notes', { placeholder={$t('placeholder.notes', {
values: { name: localUser.first_name || '' } values: { name: user.first_name || '' }
})} })}
rows={10} rows={10}
/> />
{/if} {/if}
</div> </div>
{#if hasPrivilige(localUser, PERMISSIONS.Member)} {#if hasPrivilige(user, PERMISSIONS.Member)}
<div class="tab-content" style="display: {activeTab === 'licence' ? 'block' : 'none'}"> <div class="tab-content" style="display: {activeTab === 'licence' ? 'block' : 'none'}">
<InputField <InputField
name="user[licence][status]" name="user[licence][status]"
type="select" type="select"
label={$t('status')} label={$t('status')}
bind:value={localUser.licence.status} bind:value={user.licence.status}
options={licenceStatusOptions} options={licenceStatusOptions}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -358,7 +291,7 @@
name="user[licence][number]" name="user[licence][number]"
type="text" type="text"
label={$t('licence_number')} label={$t('licence_number')}
bind:value={localUser.licence.number} bind:value={user.licence.number}
placeholder={$t('placeholder.licence_number')} placeholder={$t('placeholder.licence_number')}
toUpperCase={true} toUpperCase={true}
readonly={readonlyUser} readonly={readonlyUser}
@@ -367,7 +300,7 @@
name="user[licence][issued_date]" name="user[licence][issued_date]"
type="date" type="date"
label={$t('issued_date')} label={$t('issued_date')}
bind:value={localUser.licence.issued_date} bind:value={user.licence.issued_date}
placeholder={$t('placeholder.issued_date')} placeholder={$t('placeholder.issued_date')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -375,14 +308,14 @@
name="user[licence][expiration_date]" name="user[licence][expiration_date]"
type="date" type="date"
label={$t('expiration_date')} label={$t('expiration_date')}
bind:value={localUser.licence.expiration_date} bind:value={user.licence.expiration_date}
placeholder={$t('placeholder.expiration_date')} placeholder={$t('placeholder.expiration_date')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
<InputField <InputField
name="user[licence][country]" name="user[licence][country]"
label={$t('country')} label={$t('country')}
bind:value={localUser.licence.country} bind:value={user.licence.country}
placeholder={$t('placeholder.issuing_country')} placeholder={$t('placeholder.issuing_country')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -401,10 +334,8 @@
name="user[licence][categories][]" name="user[licence][categories][]"
value={JSON.stringify(category)} value={JSON.stringify(category)}
label={category.category} label={category.category}
checked={localUser.licence.categories != null && checked={user.licence.categories != null &&
localUser.licence.categories.some( user.licence.categories.some((cat) => cat.category === category.category)}
(cat) => cat.category === category.category
)}
/> />
</div> </div>
<span class="checkbox-description"> <span class="checkbox-description">
@@ -422,7 +353,7 @@
name="user[membership][status]" name="user[membership][status]"
type="select" type="select"
label={$t('status')} label={$t('status')}
bind:value={localUser.membership.status} bind:value={user.membership.status}
options={membershipStatusOptions} options={membershipStatusOptions}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -430,12 +361,12 @@
name="user[membership][subscription_model][name]" name="user[membership][subscription_model][name]"
type="select" type="select"
label={$t('subscription.subscription')} label={$t('subscription.subscription')}
bind:value={localUser.membership.subscription_model.name} bind:value={user.membership.subscription_model.name}
options={subscriptionModelOptions} options={subscriptionModelOptions}
readonly={readonlyUser} readonly={readonlyUser || !hasPrivilige(user, PERMISSIONS.Member)}
/> />
<div class="subscription-info"> <div class="subscription-info">
{#if hasPrivilige(editor, PERMISSIONS.Member)} {#if hasPrivilige(user, PERMISSIONS.Member)}
<div class="subscription-column"> <div class="subscription-column">
<p> <p>
<strong>{$t('subscription.monthly_fee')}:</strong> <strong>{$t('subscription.monthly_fee')}:</strong>
@@ -476,7 +407,7 @@
name="user[membership][start_date]" name="user[membership][start_date]"
type="date" type="date"
label={$t('start')} label={$t('start')}
bind:value={localUser.membership.start_date} bind:value={user.membership.start_date}
placeholder={$t('placeholder.start_date')} placeholder={$t('placeholder.start_date')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -484,16 +415,16 @@
name="user[membership][end_date]" name="user[membership][end_date]"
type="date" type="date"
label={$t('end')} label={$t('end')}
bind:value={localUser.membership.end_date} bind:value={user.membership.end_date}
placeholder={$t('placeholder.end_date')} placeholder={$t('placeholder.end_date')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
{#if hasPrivilige(editor, PERMISSIONS.Member)} {#if hasPrivilige(user, PERMISSIONS.Member)}
<InputField <InputField
name="user[membership][parent_member_id]" name="user[membership][parent_member_id]"
type="number" type="number"
label={$t('parent_member_id')} label={$t('parent_member_id')}
bind:value={localUser.membership.parent_member_id} bind:value={user.membership.parent_member_id}
placeholder={$t('placeholder.parent_member_id')} placeholder={$t('placeholder.parent_member_id')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -503,33 +434,34 @@
<InputField <InputField
name="user[bank_account][account_holder_name]" name="user[bank_account][account_holder_name]"
label={$t('bank_account_holder')} label={$t('bank_account_holder')}
bind:value={localUser.bank_account.account_holder_name} bind:value={user.bank_account.account_holder_name}
placeholder={$t('placeholder.bank_account_holder')} placeholder={$t('placeholder.bank_account_holder')}
/> />
<InputField <InputField
name="user[bank_account][bank_name]" name="user[bank_account][bank_name]"
label={$t('bank_name')} label={$t('bank_name')}
bind:value={localUser.bank_account.bank} bind:value={user.bank_account.bank}
placeholder={$t('placeholder.bank_name')} placeholder={$t('placeholder.bank_name')}
/> />
<InputField <InputField
name="user[bank_account][iban]" name="user[bank_account][iban]"
label={$t('iban')} label={$t('iban')}
bind:value={localUser.bank_account.iban} bind:value={user.bank_account.iban}
placeholder={$t('placeholder.iban')} placeholder={$t('placeholder.iban')}
required={true}
toUpperCase={true} toUpperCase={true}
/> />
<InputField <InputField
name="user[bank_account][bic]" name="user[bank_account][bic]"
label={$t('bic')} label={$t('bic')}
bind:value={localUser.bank_account.bic} bind:value={user.bank_account.bic}
placeholder={$t('placeholder.bic')} placeholder={$t('placeholder.bic')}
toUpperCase={true} toUpperCase={true}
/> />
<InputField <InputField
name="user[bank_account][mandate_reference]" name="user[bank_account][mandate_reference]"
label={$t('mandate_reference')} label={$t('mandate_reference')}
bind:value={localUser.bank_account.mandate_reference} bind:value={user.bank_account.mandate_reference}
placeholder={$t('placeholder.mandate_reference')} placeholder={$t('placeholder.mandate_reference')}
readonly={readonlyUser} readonly={readonlyUser}
/> />
@@ -537,7 +469,7 @@
name="user[bank_account][mandate_date_signed]" name="user[bank_account][mandate_date_signed]"
label={$t('mandate_date_signed')} label={$t('mandate_date_signed')}
type="date" type="date"
bind:value={localUser.bank_account.mandate_date_signed} bind:value={user.bank_account.mandate_date_signed}
readonly={true} readonly={true}
/> />
</div> </div>

View File

@@ -10,3 +10,5 @@ export const PERMISSIONS = {
Delete: 4, Delete: 4,
Super: 8 Super: 8
}; };
export const SUPPORTER_SUBSCRIPTION_MODEL_NAME = 'Keins';

View File

@@ -0,0 +1,119 @@
// src/lib/utils/defaults.js
import { SUPPORTER_SUBSCRIPTION_MODEL_NAME } from './constants';
/**
* @returns {App.Types['subscription']}
*/
export function defaultSubscription() {
return {
id: 0,
name: '',
details: '',
conditions: '',
monthly_fee: 0,
hourly_rate: 0,
included_hours_per_year: 0,
included_hours_per_month: 0
};
}
/**
* @returns {App.Types['membership']}
*/
export function defaultMembership() {
return {
id: 0,
status: 3,
start_date: '',
end_date: '',
parent_member_id: 0,
subscription_model: defaultSubscription()
};
}
/**
* @returns {App.Types['bankAccount']}
*/
export function defaultBankAccount() {
return {
id: 0,
mandate_date_signed: '',
bank: '',
account_holder_name: '',
iban: '',
bic: '',
mandate_reference: ''
};
}
/**
* @returns {App.Types['licence']}
*/
export function defaultLicence() {
return {
id: 0,
status: 0,
number: '',
issued_date: '',
expiration_date: '',
country: '',
categories: []
};
}
/**
* @returns {App.Locals['user']}
*/
export function defaultUser() {
return {
id: 0,
email: '',
first_name: '',
last_name: '',
password: '',
phone: '',
address: '',
zip_code: '',
city: '',
company: '',
dateofbirth: '',
notes: '',
profile_picture: '',
payment_status: 0,
status: 1,
role_id: 1,
membership: defaultMembership(),
licence: defaultLicence(),
bank_account: defaultBankAccount()
};
}
/**
* @returns {App.Locals['user']}
*/
export function defaultSupporter() {
let supporter = {
id: 0,
email: '',
first_name: '',
last_name: '',
password: '',
phone: '',
address: '',
zip_code: '',
city: '',
company: '',
dateofbirth: '',
notes: '',
profile_picture: '',
payment_status: 0,
status: 1,
role_id: 0,
membership: defaultMembership(),
licence: defaultLicence(),
bank_account: defaultBankAccount()
};
supporter.membership.subscription_model.name = SUPPORTER_SUBSCRIPTION_MODEL_NAME;
return supporter;
}

View File

@@ -8,6 +8,7 @@
import { applyAction, enhance } from '$app/forms'; import { applyAction, enhance } from '$app/forms';
import { hasPrivilige, receive, send } from '$lib/utils/helpers'; import { hasPrivilige, receive, send } from '$lib/utils/helpers';
import { PERMISSIONS } from '$lib/utils/constants'; import { PERMISSIONS } from '$lib/utils/constants';
import { defaultSupporter, defaultUser } from '$lib/utils/defaults';
/** @type {import('./$types').ActionData} */ /** @type {import('./$types').ActionData} */
export let form; export let form;
@@ -96,7 +97,7 @@
/** /**
* Opens the edit modal for the selected user. * Opens the edit modal for the selected user.
* @param {App.Locals['user'] | null} user The user to edit. * @param {App.Locals['user']} user The user to edit.
*/ */
const openEditUserModal = (user) => { const openEditUserModal = (user) => {
selectedUser = user; selectedUser = user;
@@ -213,7 +214,7 @@
</button> </button>
</div> </div>
<div> <div>
<button class="btn primary" on:click={() => openEditUserModal(null)}> <button class="btn primary" on:click={() => openEditUserModal(defaultUser())}>
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
{$t('add_new')} {$t('add_new')}
</button> </button>
@@ -314,7 +315,7 @@
</button> </button>
</div> </div>
<div> <div>
<button class="btn primary" on:click={() => openEditUserModal(null)}> <button class="btn primary" on:click={() => openEditUserModal(defaultSupporter())}>
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
{$t('add_new')} {$t('add_new')}
</button> </button>
@@ -330,21 +331,17 @@
<div class="accordion-content"> <div class="accordion-content">
<table class="table"> <table class="table">
<tbody> <tbody>
<tr>
<th>{$t('user.id')}</th>
<td>{user.id}</td>
</tr>
<tr> <tr>
<th>{$t('name')}</th> <th>{$t('name')}</th>
<td>{user.first_name} {user.last_name}</td> <td>{user.first_name} {user.last_name}</td>
</tr> </tr>
<tr> <tr>
<th>{$t('user.email')}</th> <th>{$t('company')}</th>
<td>{user.email}</td> <td>{user.company}</td>
</tr> </tr>
<tr> <tr>
<th>{$t('subscription.subscription')}</th> <th>{$t('user.email')}</th>
<td>{user.membership?.subscription_model?.name}</td> <td>{user.email}</td>
</tr> </tr>
<tr> <tr>
<th>{$t('status')}</th> <th>{$t('status')}</th>
@@ -536,7 +533,7 @@
</div> </div>
</div> </div>
{#if showUserModal} {#if showUserModal && selectedUser !== null}
<Modal on:close={close}> <Modal on:close={close}>
<UserEditForm <UserEditForm
{form} {form}