Compare commits
3 Commits
ac0b7234d4
...
29f405385e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29f405385e | ||
|
|
298ef9843e | ||
|
|
aa1bd00e80 |
@@ -5,6 +5,8 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
|
import { PERMISSIONS } from '$lib/utils/constants';
|
||||||
|
import { hasPrivilige } from '$lib/utils/helpers';
|
||||||
|
|
||||||
let isMobileMenuOpen = false;
|
let isMobileMenuOpen = false;
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@
|
|||||||
{$page.data.user.last_name}
|
{$page.data.user.last_name}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{#if $page.data.user.role_id > 0}
|
{#if hasPrivilige($page.data.user, PERMISSIONS.View)}
|
||||||
<div
|
<div
|
||||||
class="header-nav-item"
|
class="header-nav-item"
|
||||||
class:active={$page.url.pathname.startsWith(`${base}/auth/admin/users`)}
|
class:active={$page.url.pathname.startsWith(`${base}/auth/admin/users`)}
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
import SmallLoader from '$lib/components/SmallLoader.svelte';
|
import SmallLoader from '$lib/components/SmallLoader.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { applyAction, enhance } from '$app/forms';
|
import { applyAction, enhance } from '$app/forms';
|
||||||
import { receive, send } from '$lib/utils/helpers';
|
import { hasPrivilige, receive, send } from '$lib/utils/helpers';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import { PERMISSIONS } from '$lib/utils/constants';
|
||||||
|
|
||||||
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
|
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
|
||||||
export let form;
|
export let form;
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
profile_picture: '',
|
profile_picture: '',
|
||||||
payment_status: 0,
|
payment_status: 0,
|
||||||
status: 1,
|
status: 1,
|
||||||
role_id: 0,
|
role_id: 1,
|
||||||
membership: {
|
membership: {
|
||||||
id: 0,
|
id: 0,
|
||||||
start_date: '',
|
start_date: '',
|
||||||
@@ -70,12 +71,14 @@
|
|||||||
/** @type {App.Locals['user'] | null} */
|
/** @type {App.Locals['user'] | null} */
|
||||||
export let user;
|
export let user;
|
||||||
|
|
||||||
/** @type {Number} */
|
/** @type {App.Locals['user']} */
|
||||||
export let role_id;
|
export let editor;
|
||||||
|
|
||||||
/** @type {App.Locals['user'] } */
|
/** @type {App.Locals['user'] } */
|
||||||
let localUser;
|
let localUser;
|
||||||
|
|
||||||
|
let readonlyUser = !hasPrivilige(editor, PERMISSIONS.Update);
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (user !== undefined && !localUser) {
|
if (user !== undefined && !localUser) {
|
||||||
localUser =
|
localUser =
|
||||||
@@ -106,8 +109,9 @@
|
|||||||
const userRoleOptions = [
|
const userRoleOptions = [
|
||||||
{ value: 0, label: $t('userRole.0'), color: '--subtext1' }, // Grey for "Nicht verifiziert"
|
{ value: 0, label: $t('userRole.0'), color: '--subtext1' }, // Grey for "Nicht verifiziert"
|
||||||
{ value: 1, label: $t('userRole.1'), color: '--light-green' }, // Light green for "Verifiziert"
|
{ value: 1, label: $t('userRole.1'), color: '--light-green' }, // Light green for "Verifiziert"
|
||||||
{ value: 4, label: $t('userRole.4'), color: '--green' }, // Green for "Aktiv"
|
{ value: 2, label: $t('userRole.2'), color: '--green' }, // Light green for "Verifiziert"
|
||||||
{ value: 8, label: $t('userRole.8'), color: '--pink' } // Pink for "Passiv"
|
{ value: 4, label: $t('userRole.4'), color: '--pink' }, // Green for "Aktiv"
|
||||||
|
{ value: 8, label: $t('userRole.8'), color: '--red' } // Pink for "Passiv"
|
||||||
];
|
];
|
||||||
const membershipStatusOptions = [
|
const membershipStatusOptions = [
|
||||||
{ value: 3, label: $t('userStatus.3'), color: '--green' }, // Green for "Aktiv"
|
{ value: 3, label: $t('userStatus.3'), color: '--green' }, // Green for "Aktiv"
|
||||||
@@ -232,9 +236,9 @@
|
|||||||
label={$t('status')}
|
label={$t('status')}
|
||||||
bind:value={localUser.status}
|
bind:value={localUser.status}
|
||||||
options={userStatusOptions}
|
options={userStatusOptions}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
{#if role_id === 8}
|
{#if hasPrivilige(editor, PERMISSIONS.Super)}
|
||||||
<InputField
|
<InputField
|
||||||
name="user[role_id]"
|
name="user[role_id]"
|
||||||
type="select"
|
type="select"
|
||||||
@@ -243,29 +247,31 @@
|
|||||||
options={userRoleOptions}
|
options={userRoleOptions}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<InputField
|
{#if hasPrivilige(localUser, PERMISSIONS.Member)}
|
||||||
name="user[password]"
|
<InputField
|
||||||
type="password"
|
name="user[password]"
|
||||||
label={$t('password')}
|
type="password"
|
||||||
placeholder={$t('placeholder.password')}
|
label={$t('password')}
|
||||||
bind:value={password}
|
placeholder={$t('placeholder.password')}
|
||||||
otherPasswordValue={confirm_password}
|
bind:value={password}
|
||||||
/>
|
otherPasswordValue={confirm_password}
|
||||||
<InputField
|
/>
|
||||||
name="confirm_password"
|
<InputField
|
||||||
type="password"
|
name="confirm_password"
|
||||||
label={$t('confirm_password')}
|
type="password"
|
||||||
placeholder={$t('placeholder.password')}
|
label={$t('confirm_password')}
|
||||||
bind:value={confirm_password}
|
placeholder={$t('placeholder.password')}
|
||||||
otherPasswordValue={password}
|
bind:value={confirm_password}
|
||||||
/>
|
otherPasswordValue={password}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
<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={localUser.first_name}
|
||||||
placeholder={$t('placeholder.first_name')}
|
placeholder={$t('placeholder.first_name')}
|
||||||
required={true}
|
required={true}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[last_name]"
|
name="user[last_name]"
|
||||||
@@ -273,7 +279,7 @@
|
|||||||
bind:value={localUser.last_name}
|
bind:value={localUser.last_name}
|
||||||
placeholder={$t('placeholder.last_name')}
|
placeholder={$t('placeholder.last_name')}
|
||||||
required={true}
|
required={true}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[company]"
|
name="user[company]"
|
||||||
@@ -296,14 +302,16 @@
|
|||||||
bind:value={localUser.phone}
|
bind:value={localUser.phone}
|
||||||
placeholder={$t('placeholder.phone')}
|
placeholder={$t('placeholder.phone')}
|
||||||
/>
|
/>
|
||||||
<InputField
|
{#if hasPrivilige(localUser, PERMISSIONS.Member)}
|
||||||
name="user[dateofbirth]"
|
<InputField
|
||||||
type="date"
|
name="user[dateofbirth]"
|
||||||
label={$t('user.dateofbirth')}
|
type="date"
|
||||||
bind:value={localUser.dateofbirth}
|
label={$t('user.dateofbirth')}
|
||||||
placeholder={$t('placeholder.dateofbirth')}
|
bind:value={localUser.dateofbirth}
|
||||||
readonly={role_id === 0}
|
placeholder={$t('placeholder.dateofbirth')}
|
||||||
/>
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
<InputField
|
<InputField
|
||||||
name="user[address]"
|
name="user[address]"
|
||||||
label={$t('address')}
|
label={$t('address')}
|
||||||
@@ -322,7 +330,7 @@
|
|||||||
bind:value={localUser.city}
|
bind:value={localUser.city}
|
||||||
placeholder={$t('placeholder.city')}
|
placeholder={$t('placeholder.city')}
|
||||||
/>
|
/>
|
||||||
{#if role_id > 0}
|
{#if !readonlyUser}
|
||||||
<InputField
|
<InputField
|
||||||
name="user[notes]"
|
name="user[notes]"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
@@ -335,77 +343,80 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content" style="display: {activeTab === 'licence' ? 'block' : 'none'}">
|
|
||||||
<InputField
|
{#if hasPrivilige(localUser, PERMISSIONS.Member)}
|
||||||
name="user[licence][status]"
|
<div class="tab-content" style="display: {activeTab === 'licence' ? 'block' : 'none'}">
|
||||||
type="select"
|
<InputField
|
||||||
label={$t('status')}
|
name="user[licence][status]"
|
||||||
bind:value={localUser.licence.status}
|
type="select"
|
||||||
options={licenceStatusOptions}
|
label={$t('status')}
|
||||||
readonly={role_id === 0}
|
bind:value={localUser.licence.status}
|
||||||
/>
|
options={licenceStatusOptions}
|
||||||
<InputField
|
readonly={readonlyUser}
|
||||||
name="user[licence][number]"
|
/>
|
||||||
type="text"
|
<InputField
|
||||||
label={$t('licence_number')}
|
name="user[licence][number]"
|
||||||
bind:value={localUser.licence.number}
|
type="text"
|
||||||
placeholder={$t('placeholder.licence_number')}
|
label={$t('licence_number')}
|
||||||
toUpperCase={true}
|
bind:value={localUser.licence.number}
|
||||||
readonly={role_id === 0}
|
placeholder={$t('placeholder.licence_number')}
|
||||||
/>
|
toUpperCase={true}
|
||||||
<InputField
|
readonly={readonlyUser}
|
||||||
name="user[licence][issued_date]"
|
/>
|
||||||
type="date"
|
<InputField
|
||||||
label={$t('issued_date')}
|
name="user[licence][issued_date]"
|
||||||
bind:value={localUser.licence.issued_date}
|
type="date"
|
||||||
placeholder={$t('placeholder.issued_date')}
|
label={$t('issued_date')}
|
||||||
readonly={role_id === 0}
|
bind:value={localUser.licence.issued_date}
|
||||||
/>
|
placeholder={$t('placeholder.issued_date')}
|
||||||
<InputField
|
readonly={readonlyUser}
|
||||||
name="user[licence][expiration_date]"
|
/>
|
||||||
type="date"
|
<InputField
|
||||||
label={$t('expiration_date')}
|
name="user[licence][expiration_date]"
|
||||||
bind:value={localUser.licence.expiration_date}
|
type="date"
|
||||||
placeholder={$t('placeholder.expiration_date')}
|
label={$t('expiration_date')}
|
||||||
readonly={role_id === 0}
|
bind:value={localUser.licence.expiration_date}
|
||||||
/>
|
placeholder={$t('placeholder.expiration_date')}
|
||||||
<InputField
|
readonly={readonlyUser}
|
||||||
name="user[licence][country]"
|
/>
|
||||||
label={$t('country')}
|
<InputField
|
||||||
bind:value={localUser.licence.country}
|
name="user[licence][country]"
|
||||||
placeholder={$t('placeholder.issuing_country')}
|
label={$t('country')}
|
||||||
readonly={role_id === 0}
|
bind:value={localUser.licence.country}
|
||||||
/>
|
placeholder={$t('placeholder.issuing_country')}
|
||||||
<div class="licence-categories">
|
readonly={readonlyUser}
|
||||||
<h3>{$t('licence_categories')}</h3>
|
/>
|
||||||
<div class="checkbox-grid">
|
<div class="licence-categories">
|
||||||
{#each Object.entries(groupedCategories) as [, categories], groupIndex}
|
<h3>{$t('licence_categories')}</h3>
|
||||||
{#if groupIndex > 0}
|
<div class="checkbox-grid">
|
||||||
<div class="category-break"></div>
|
{#each Object.entries(groupedCategories) as [, categories], groupIndex}
|
||||||
{/if}
|
{#if groupIndex > 0}
|
||||||
{#each categories as category}
|
<div class="category-break"></div>
|
||||||
<div class="checkbox-item">
|
{/if}
|
||||||
<div class="checkbox-label-container">
|
{#each categories as category}
|
||||||
<InputField
|
<div class="checkbox-item">
|
||||||
type="checkbox"
|
<div class="checkbox-label-container">
|
||||||
name="user[licence][categories][]"
|
<InputField
|
||||||
value={JSON.stringify(category)}
|
type="checkbox"
|
||||||
label={category.category}
|
name="user[licence][categories][]"
|
||||||
checked={localUser.licence.categories != null &&
|
value={JSON.stringify(category)}
|
||||||
localUser.licence.categories.some(
|
label={category.category}
|
||||||
(cat) => cat.category === category.category
|
checked={localUser.licence.categories != null &&
|
||||||
)}
|
localUser.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}
|
||||||
{/each}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
<div class="tab-content" style="display: {activeTab === 'membership' ? 'block' : 'none'}">
|
<div class="tab-content" style="display: {activeTab === 'membership' ? 'block' : 'none'}">
|
||||||
<InputField
|
<InputField
|
||||||
name="user[membership][status]"
|
name="user[membership][status]"
|
||||||
@@ -413,7 +424,7 @@
|
|||||||
label={$t('status')}
|
label={$t('status')}
|
||||||
bind:value={localUser.membership.status}
|
bind:value={localUser.membership.status}
|
||||||
options={membershipStatusOptions}
|
options={membershipStatusOptions}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[membership][subscription_model][name]"
|
name="user[membership][subscription_model][name]"
|
||||||
@@ -421,31 +432,33 @@
|
|||||||
label={$t('subscription.subscription')}
|
label={$t('subscription.subscription')}
|
||||||
bind:value={localUser.membership.subscription_model.name}
|
bind:value={localUser.membership.subscription_model.name}
|
||||||
options={subscriptionModelOptions}
|
options={subscriptionModelOptions}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<div class="subscription-info">
|
<div class="subscription-info">
|
||||||
<div class="subscription-column">
|
{#if hasPrivilige(editor, PERMISSIONS.Member)}
|
||||||
<p>
|
<div class="subscription-column">
|
||||||
<strong>{$t('subscription.monthly_fee')}:</strong>
|
|
||||||
{selectedSubscriptionModel?.monthly_fee || '-'} €
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{$t('subscription.hourly_rate')}:</strong>
|
|
||||||
{selectedSubscriptionModel?.hourly_rate || '-'} €
|
|
||||||
</p>
|
|
||||||
{#if selectedSubscriptionModel?.included_hours_per_year}
|
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('subscription.included_hours_per_year')}:</strong>
|
<strong>{$t('subscription.monthly_fee')}:</strong>
|
||||||
{selectedSubscriptionModel?.included_hours_per_year}
|
{selectedSubscriptionModel?.monthly_fee || '-'} €
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
|
||||||
{#if selectedSubscriptionModel?.included_hours_per_month}
|
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('subscription.included_hours_per_month')}:</strong>
|
<strong>{$t('subscription.hourly_rate')}:</strong>
|
||||||
{selectedSubscriptionModel?.included_hours_per_month}
|
{selectedSubscriptionModel?.hourly_rate || '-'} €
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{#if selectedSubscriptionModel?.included_hours_per_year}
|
||||||
</div>
|
<p>
|
||||||
|
<strong>{$t('subscription.included_hours_per_year')}:</strong>
|
||||||
|
{selectedSubscriptionModel?.included_hours_per_year}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
{#if selectedSubscriptionModel?.included_hours_per_month}
|
||||||
|
<p>
|
||||||
|
<strong>{$t('subscription.included_hours_per_month')}:</strong>
|
||||||
|
{selectedSubscriptionModel?.included_hours_per_month}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="subscription-column">
|
<div class="subscription-column">
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('details')}:</strong>
|
<strong>{$t('details')}:</strong>
|
||||||
@@ -465,7 +478,7 @@
|
|||||||
label={$t('start')}
|
label={$t('start')}
|
||||||
bind:value={localUser.membership.start_date}
|
bind:value={localUser.membership.start_date}
|
||||||
placeholder={$t('placeholder.start_date')}
|
placeholder={$t('placeholder.start_date')}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[membership][end_date]"
|
name="user[membership][end_date]"
|
||||||
@@ -473,16 +486,18 @@
|
|||||||
label={$t('end')}
|
label={$t('end')}
|
||||||
bind:value={localUser.membership.end_date}
|
bind:value={localUser.membership.end_date}
|
||||||
placeholder={$t('placeholder.end_date')}
|
placeholder={$t('placeholder.end_date')}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
|
||||||
<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')}
|
|
||||||
readonly={role_id === 0}
|
|
||||||
/>
|
/>
|
||||||
|
{#if hasPrivilige(editor, PERMISSIONS.Member)}
|
||||||
|
<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')}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content" style="display: {activeTab === 'bankaccount' ? 'block' : 'none'}">
|
<div class="tab-content" style="display: {activeTab === 'bankaccount' ? 'block' : 'none'}">
|
||||||
<InputField
|
<InputField
|
||||||
@@ -516,7 +531,7 @@
|
|||||||
label={$t('mandate_reference')}
|
label={$t('mandate_reference')}
|
||||||
bind:value={localUser.bank_account.mandate_reference}
|
bind:value={localUser.bank_account.mandate_reference}
|
||||||
placeholder={$t('placeholder.mandate_reference')}
|
placeholder={$t('placeholder.mandate_reference')}
|
||||||
readonly={role_id === 0}
|
readonly={readonlyUser}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[bank_account][mandate_date_signed]"
|
name="user[bank_account][mandate_date_signed]"
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ export default {
|
|||||||
1: 'Nicht verifiziert',
|
1: 'Nicht verifiziert',
|
||||||
2: 'Deaktiviert',
|
2: 'Deaktiviert',
|
||||||
3: 'Verifiziert',
|
3: 'Verifiziert',
|
||||||
4: 'Aktiv',
|
4: 'Systemzugang',
|
||||||
5: 'Passiv'
|
5: 'Passiv'
|
||||||
},
|
},
|
||||||
userRole: {
|
userRole: {
|
||||||
0: 'Mitglied',
|
0: 'Sponsor',
|
||||||
1: 'Betrachter',
|
1: 'Mitglied',
|
||||||
|
2: 'Betrachter',
|
||||||
4: 'Bearbeiter',
|
4: 'Bearbeiter',
|
||||||
8: 'Administrator'
|
8: 'Administrator'
|
||||||
},
|
},
|
||||||
@@ -124,7 +125,8 @@ export default {
|
|||||||
dateofbirth: 'Geburtstag',
|
dateofbirth: 'Geburtstag',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
role: 'Nutzerrolle'
|
role: 'Nutzerrolle',
|
||||||
|
supporter: 'Sponsor'
|
||||||
},
|
},
|
||||||
subscription: {
|
subscription: {
|
||||||
name: 'Modellname',
|
name: 'Modellname',
|
||||||
@@ -155,6 +157,7 @@ export default {
|
|||||||
delete: 'Löschen',
|
delete: 'Löschen',
|
||||||
search: 'Suche:',
|
search: 'Suche:',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
|
supporter: 'Sponsoren',
|
||||||
mandate_date_signed: 'Mandatserteilungsdatum',
|
mandate_date_signed: 'Mandatserteilungsdatum',
|
||||||
licence_categories: 'Führerscheinklassen',
|
licence_categories: 'Führerscheinklassen',
|
||||||
subscription_model: 'Mitgliedschatfsmodell',
|
subscription_model: 'Mitgliedschatfsmodell',
|
||||||
|
|||||||
@@ -1,15 +1,210 @@
|
|||||||
export default {
|
export default {
|
||||||
userStatus: {
|
userStatus: {
|
||||||
1: "Unverified",
|
1: 'Not Verified',
|
||||||
2: "Verified",
|
2: 'Deactivated',
|
||||||
3: "Active",
|
3: 'Verified',
|
||||||
4: "Passive",
|
4: 'System Access',
|
||||||
5: "Disabled",
|
5: 'Passive'
|
||||||
},
|
},
|
||||||
userRole: {
|
userRole: {
|
||||||
0: "Member",
|
0: 'Sponsor',
|
||||||
1: "Viewer",
|
1: 'Member',
|
||||||
4: "Editor",
|
2: 'Viewer',
|
||||||
8: "Admin",
|
4: 'Editor',
|
||||||
},
|
8: 'Administrator'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
password: 'Enter password...',
|
||||||
|
email: 'Enter email address...',
|
||||||
|
company: 'Enter company name...',
|
||||||
|
first_name: 'Enter first name...',
|
||||||
|
last_name: 'Enter last name...',
|
||||||
|
phone: 'Enter phone number...',
|
||||||
|
address: 'Enter street and house number...',
|
||||||
|
zip_code: 'Enter postal code...',
|
||||||
|
city: 'Enter city...',
|
||||||
|
bank_name: 'Enter bank name...',
|
||||||
|
parent_member_id: 'Enter parent member ID...',
|
||||||
|
bank_account_holder: 'Enter name...',
|
||||||
|
iban: 'Enter IBAN...',
|
||||||
|
bic: 'Enter BIC (for non-German accounts)...',
|
||||||
|
mandate_reference: 'Enter SEPA mandate reference...',
|
||||||
|
notes: 'Your notes about {name}...',
|
||||||
|
licence_number: 'On the driver’s license under field 5',
|
||||||
|
issued_date: 'Issue date under field 4a',
|
||||||
|
expiration_date: 'Expiration date under field 4b',
|
||||||
|
issuing_country: 'Issuing country',
|
||||||
|
subscription_name: 'Subscription model name',
|
||||||
|
subscription_details: 'Describe the subscription model...',
|
||||||
|
subscription_conditions: 'Describe the usage conditions...',
|
||||||
|
search: 'Search...'
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
required: 'Input required',
|
||||||
|
password: 'Password too short, at least 8 characters',
|
||||||
|
password_match: 'Passwords do not match!',
|
||||||
|
phone: 'Invalid format (+491738762387 or 0173850698)',
|
||||||
|
zip_code: 'Invalid postal code (Only German locations are allowed)',
|
||||||
|
bic: 'Invalid BIC',
|
||||||
|
iban: 'Invalid IBAN',
|
||||||
|
date: 'Please enter a date',
|
||||||
|
email: 'Invalid email address',
|
||||||
|
licence: 'Number too short (11 characters)'
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
general: 'General',
|
||||||
|
error: {
|
||||||
|
invalid_json: 'Invalid JSON data',
|
||||||
|
no_auth_token: 'Unauthorized, missing or invalid auth token',
|
||||||
|
jwt_parsing_error: 'Unauthorized, auth token could not be read',
|
||||||
|
unauthorized: 'You are not authorized to perform this action',
|
||||||
|
internal_server_error:
|
||||||
|
'Damn, error on our side, try again, then contact someone from the organization.',
|
||||||
|
not_possible: 'Operation not possible.',
|
||||||
|
not_found: 'Could not be found.',
|
||||||
|
in_use: 'Is in use',
|
||||||
|
undelivered_verification_mail:
|
||||||
|
'Registration successful, but the verification email could not be sent. Please contact the organization to verify your email address and activate your account.'
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
invalid: 'Invalid',
|
||||||
|
invalid_user_id: 'Invalid user ID',
|
||||||
|
invalid_subscription_model: 'Model not found',
|
||||||
|
user_not_found: '{field} could not be found',
|
||||||
|
invalid_user_data: 'Invalid user data',
|
||||||
|
user_not_found_or_wrong_password: 'Does not exist or wrong password',
|
||||||
|
email_already_registered: 'A member has already been created with this email address.',
|
||||||
|
password_already_changed: 'The password has already been changed.',
|
||||||
|
alphanumunicode: 'Contains disallowed characters',
|
||||||
|
safe_content: 'I see what you did there! Do not cross this line!',
|
||||||
|
iban: 'Invalid. Format: DE07123412341234123412',
|
||||||
|
bic: 'Invalid. Format: BELADEBEXXX',
|
||||||
|
email: 'Invalid format',
|
||||||
|
number: 'Is not a number',
|
||||||
|
euDriversLicence: 'Is not a European driver’s license',
|
||||||
|
lte: 'Is too large/new',
|
||||||
|
gt: 'Is too small/old',
|
||||||
|
required: 'Field is required',
|
||||||
|
image: 'This is not an image',
|
||||||
|
alphanum: 'Contains invalid characters',
|
||||||
|
user_disabled: 'User is disabled',
|
||||||
|
duplicate: 'Already exists...',
|
||||||
|
alphaunicode: 'Must consist only of letters',
|
||||||
|
too_soon: 'Too soon'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
licenceCategory: {
|
||||||
|
AM: 'Mopeds and light four-wheeled vehicles (50cc, max 45 km/h)',
|
||||||
|
A1: 'Light motorcycles (125cc)',
|
||||||
|
A2: 'Medium-power motorcycles (max 35 kW)',
|
||||||
|
A: 'Motorcycles',
|
||||||
|
B: 'Motor vehicles ≤ 3500 kg, ≤ 8 seats',
|
||||||
|
C1: 'Medium-heavy vehicles - 7500 kg',
|
||||||
|
C: 'Heavy commercial vehicles > 3500 kg',
|
||||||
|
D1: 'Minibuses with 9-16 seats',
|
||||||
|
D: 'Buses > 8 seats',
|
||||||
|
BE: 'Vehicle class B with trailer',
|
||||||
|
C1E: 'Vehicle class C1 with trailer',
|
||||||
|
CE: 'Vehicle class C with trailer',
|
||||||
|
D1E: 'Vehicle class D1 with trailer',
|
||||||
|
DE: 'Vehicle class D with trailer',
|
||||||
|
L: 'Agricultural, forestry vehicles, forklifts max 40 km/h',
|
||||||
|
T: 'Agricultural, forestry vehicles, forklifts max 60 km/h'
|
||||||
|
},
|
||||||
|
users: 'Members',
|
||||||
|
user: {
|
||||||
|
login: 'User Login',
|
||||||
|
edit: 'Edit User',
|
||||||
|
create: 'Create User',
|
||||||
|
user: 'User',
|
||||||
|
management: 'Member Management',
|
||||||
|
id: 'Member ID',
|
||||||
|
first_name: 'First Name',
|
||||||
|
last_name: 'Last Name',
|
||||||
|
phone: 'Phone Number',
|
||||||
|
dateofbirth: 'Date of Birth',
|
||||||
|
email: 'Email',
|
||||||
|
status: 'Status',
|
||||||
|
role: 'User Role',
|
||||||
|
supporter: 'Sponsor'
|
||||||
|
},
|
||||||
|
subscription: {
|
||||||
|
name: 'Model Name',
|
||||||
|
edit: 'Edit Model',
|
||||||
|
create: 'Create Model',
|
||||||
|
subscription: 'Subscription Model',
|
||||||
|
subscriptions: 'Subscription Models',
|
||||||
|
conditions: 'Conditions',
|
||||||
|
monthly_fee: 'Monthly Fee',
|
||||||
|
hourly_rate: 'Hourly Rate',
|
||||||
|
included_hours_per_year: 'Included Hours Per Year',
|
||||||
|
included_hours_per_month: 'Included Hours Per Month'
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
user_data: 'Loading user data',
|
||||||
|
subscription_data: 'Loading model data',
|
||||||
|
please_wait: 'Please wait...',
|
||||||
|
updating: 'Updating...'
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
user_deletion: 'Should the user {firstname} {lastname} really be deleted?',
|
||||||
|
subscription_deletion: 'Should the subscription model {name} really be deleted?'
|
||||||
|
},
|
||||||
|
cancel: 'Cancel',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
actions: 'Actions',
|
||||||
|
edit: 'Edit',
|
||||||
|
delete: 'Delete',
|
||||||
|
search: 'Search:',
|
||||||
|
name: 'Name',
|
||||||
|
supporter: 'Sponsors',
|
||||||
|
mandate_date_signed: 'Mandate Signing Date',
|
||||||
|
licence_categories: 'Driver’s License Categories',
|
||||||
|
subscription_model: 'Membership Model',
|
||||||
|
licence: 'Driver’s License',
|
||||||
|
licence_number: 'Driver’s License Number',
|
||||||
|
issued_date: 'Issue Date',
|
||||||
|
expiration_date: 'Expiration Date',
|
||||||
|
country: 'Country',
|
||||||
|
details: 'Details',
|
||||||
|
unknown: 'Unknown',
|
||||||
|
notes: 'Notes',
|
||||||
|
address: 'Street & House Number',
|
||||||
|
city: 'City',
|
||||||
|
zip_code: 'ZIP Code',
|
||||||
|
forgot_password: 'Forgot Password?',
|
||||||
|
password: 'Password',
|
||||||
|
confirm_password: 'Repeat Password',
|
||||||
|
password_changed: 'Password successfully changed.',
|
||||||
|
change_password: 'Change Password',
|
||||||
|
password_change_requested: 'Password change request sent... Please check your inbox.',
|
||||||
|
company: 'Company',
|
||||||
|
login: 'Login',
|
||||||
|
profile: 'Profile',
|
||||||
|
membership: 'Membership',
|
||||||
|
bankaccount: 'Bank Account',
|
||||||
|
status: 'Status',
|
||||||
|
start: 'Start',
|
||||||
|
end: 'End',
|
||||||
|
parent_member_id: 'Parent Member ID',
|
||||||
|
bank_account_holder: 'Account Holder',
|
||||||
|
bank_name: 'Bank Name',
|
||||||
|
iban: 'IBAN',
|
||||||
|
bic: 'BIC',
|
||||||
|
mandate_reference: 'SEPA Mandate',
|
||||||
|
payments: 'Payments',
|
||||||
|
add_new: 'New',
|
||||||
|
email_sent: 'Email has been sent...',
|
||||||
|
payment: {
|
||||||
|
id: 'Payment ID',
|
||||||
|
amount: 'Amount',
|
||||||
|
date: 'Date',
|
||||||
|
status: 'Status'
|
||||||
|
},
|
||||||
|
subscriptionStatus: {
|
||||||
|
pending: 'Pending',
|
||||||
|
completed: 'Completed',
|
||||||
|
failed: 'Failed',
|
||||||
|
cancelled: 'Cancelled'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
export const BASE_API_URI = import.meta.env.DEV
|
export const BASE_API_URI = import.meta.env.DEV
|
||||||
? import.meta.env.VITE_BASE_API_URI_DEV
|
? import.meta.env.VITE_BASE_API_URI_DEV
|
||||||
: import.meta.env.VITE_BASE_API_URI_PROD;
|
: import.meta.env.VITE_BASE_API_URI_PROD;
|
||||||
|
|
||||||
|
export const PERMISSIONS = {
|
||||||
|
Member: 1,
|
||||||
|
View: 2,
|
||||||
|
Update: 4,
|
||||||
|
Create: 4,
|
||||||
|
Delete: 4,
|
||||||
|
Super: 8
|
||||||
|
};
|
||||||
|
|||||||
@@ -200,3 +200,13 @@ export function refreshCookie(newToken, cookies) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks the permission of the user
|
||||||
|
* @param {App.Locals['user']} user - The user object
|
||||||
|
* @param {number} required_permission - The required permission
|
||||||
|
* @returns {boolean} - True if the user has the required permission
|
||||||
|
*/
|
||||||
|
export function hasPrivilige(user, required_permission) {
|
||||||
|
return user.role_id >= required_permission;
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
default: 'unknown status'
|
default: 'unknown status'
|
||||||
})}</span
|
})}</span
|
||||||
>
|
>
|
||||||
<span>{$t(`userRole.${user.role_id}`, { default: 'unknown role' })}</span>
|
<span>{$t(`userRole.${user.role_id}`, { default: 'unknown' })}</span>
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
{licence_categories}
|
{licence_categories}
|
||||||
on:close={close}
|
on:close={close}
|
||||||
on:cancel={close}
|
on:cancel={close}
|
||||||
role_id={user.role_id}
|
editor={user}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// - Implement a load function to fetch a list of all users.
|
// - Implement a load function to fetch a list of all users.
|
||||||
// - Create actions for updating user information (similar to the about/[id] route).
|
// - Create actions for updating user information (similar to the about/[id] route).
|
||||||
|
|
||||||
import { BASE_API_URI } from '$lib/utils/constants';
|
import { BASE_API_URI, PERMISSIONS } from '$lib/utils/constants';
|
||||||
import { formatError, userDatesFromRFC3339 } from '$lib/utils/helpers';
|
import { formatError, hasPrivilige, userDatesFromRFC3339 } from '$lib/utils/helpers';
|
||||||
import { fail, redirect } from '@sveltejs/kit';
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
import {
|
import {
|
||||||
formDataToObject,
|
formDataToObject,
|
||||||
@@ -18,7 +18,7 @@ export async function load({ locals }) {
|
|||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
throw redirect(302, `${base}/auth/login?next=${base}/auth/admin/users`);
|
throw redirect(302, `${base}/auth/login?next=${base}/auth/admin/users`);
|
||||||
}
|
}
|
||||||
if (locals.user.role_id === 0) {
|
if (!hasPrivilige(locals.user, PERMISSIONS.View)) {
|
||||||
throw redirect(302, `${base}/auth/about/${locals.user.id}`);
|
throw redirect(302, `${base}/auth/about/${locals.user.id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { applyAction, enhance } from '$app/forms';
|
import { applyAction, enhance } from '$app/forms';
|
||||||
import { receive, send } from '$lib/utils/helpers';
|
import { hasPrivilige, receive, send } from '$lib/utils/helpers';
|
||||||
|
import { PERMISSIONS } from '$lib/utils/constants';
|
||||||
|
|
||||||
/** @type {import('./$types').ActionData} */
|
/** @type {import('./$types').ActionData} */
|
||||||
export let form;
|
export let form;
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
payments = []
|
payments = []
|
||||||
} = $page.data);
|
} = $page.data);
|
||||||
|
|
||||||
let activeSection = 'users';
|
let activeSection = 'members';
|
||||||
/** @type{App.Locals['user'] | null} */
|
/** @type{App.Locals['user'] | null} */
|
||||||
let selectedUser = null;
|
let selectedUser = null;
|
||||||
/** @type{App.Types['subscription'] | null} */
|
/** @type{App.Types['subscription'] | null} */
|
||||||
@@ -28,9 +29,21 @@
|
|||||||
let showUserModal = false;
|
let showUserModal = false;
|
||||||
let searchTerm = '';
|
let searchTerm = '';
|
||||||
|
|
||||||
$: filteredUsers = searchTerm ? getFilteredUsers() : users;
|
$: members = users.filter((/** @type{App.Locals['user']} */ user) => {
|
||||||
|
return user.role_id >= PERMISSIONS.Member;
|
||||||
|
});
|
||||||
|
$: supporters = users.filter((/** @type{App.Locals['user']} */ user) => {
|
||||||
|
return user.role_id < PERMISSIONS.Member;
|
||||||
|
});
|
||||||
|
$: filteredMembers = searchTerm ? getFilteredUsers(members) : members;
|
||||||
|
|
||||||
function handleMailButtonClick() {
|
$: filteredSupporters = searchTerm ? getFilteredUsers(supporters) : supporters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles Mail button click to open a formatted mailto link
|
||||||
|
* @param {App.Locals['user'][]} filteredUsers - the users to send the mail to
|
||||||
|
*/
|
||||||
|
function handleMailButtonClick(filteredUsers) {
|
||||||
const subject = 'Important Announcement';
|
const subject = 'Important Announcement';
|
||||||
const body = `Hello everyone,\n\nThis is an important message.`;
|
const body = `Hello everyone,\n\nThis is an important message.`;
|
||||||
const bccEmails = filteredUsers
|
const bccEmails = filteredUsers
|
||||||
@@ -43,14 +56,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns a set of users depending on the entered search query
|
* returns a set of members depending on the entered search query
|
||||||
|
* @param {App.Locals['user'][]} userSet Set to filter
|
||||||
* @return {App.Locals['user'][]}*/
|
* @return {App.Locals['user'][]}*/
|
||||||
const getFilteredUsers = () => {
|
const getFilteredUsers = (userSet) => {
|
||||||
if (!searchTerm.trim()) return users;
|
if (!searchTerm.trim()) return userSet;
|
||||||
|
|
||||||
const term = searchTerm.trim().toLowerCase();
|
const term = searchTerm.trim().toLowerCase();
|
||||||
|
|
||||||
return users.filter((/** @type{App.Locals['user']}*/ user) => {
|
return userSet.filter((/** @type{App.Locals['user']}*/ user) => {
|
||||||
const basicMatch = [
|
const basicMatch = [
|
||||||
user.first_name?.toLowerCase(),
|
user.first_name?.toLowerCase(),
|
||||||
user.last_name?.toLowerCase(),
|
user.last_name?.toLowerCase(),
|
||||||
@@ -124,12 +138,22 @@
|
|||||||
<ul class="nav-list">
|
<ul class="nav-list">
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
class="nav-link {activeSection === 'users' ? 'active' : ''}"
|
class="nav-link {activeSection === 'members' ? 'active' : ''}"
|
||||||
on:click={() => setActiveSection('users')}
|
on:click={() => setActiveSection('members')}
|
||||||
>
|
>
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-users"></i>
|
||||||
{$t('users')}
|
{$t('users')}
|
||||||
<span class="nav-badge">{users.length}</span>
|
<span class="nav-badge">{members.length}</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="nav-link {activeSection === 'supporter' ? 'active' : ''}"
|
||||||
|
on:click={() => setActiveSection('supporter')}
|
||||||
|
>
|
||||||
|
<i class="fas fa-hand-holding-dollar"></i>
|
||||||
|
{$t('supporter')}
|
||||||
|
<span class="nav-badge">{supporters.length}</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -168,7 +192,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if activeSection === 'users'}
|
{#if activeSection === 'members'}
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>{$t('users')}</h2>
|
<h2>{$t('users')}</h2>
|
||||||
<div class="title-container">
|
<div class="title-container">
|
||||||
@@ -183,7 +207,7 @@
|
|||||||
<button
|
<button
|
||||||
class="btn primary"
|
class="btn primary"
|
||||||
aria-label="Mail Users"
|
aria-label="Mail Users"
|
||||||
on:click={() => handleMailButtonClick()}
|
on:click={() => handleMailButtonClick(filteredMembers)}
|
||||||
>
|
>
|
||||||
<i class="fas fa-envelope"></i>
|
<i class="fas fa-envelope"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -196,7 +220,108 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion">
|
<div class="accordion">
|
||||||
{#each filteredUsers as user}
|
{#each filteredMembers as user}
|
||||||
|
<details class="accordion-item">
|
||||||
|
<summary class="accordion-header">
|
||||||
|
{user.first_name}
|
||||||
|
{user.last_name}
|
||||||
|
</summary>
|
||||||
|
<div class="accordion-content">
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>{$t('user.id')}</th>
|
||||||
|
<td>{user.id}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{$t('name')}</th>
|
||||||
|
<td>{user.first_name} {user.last_name}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{$t('user.email')}</th>
|
||||||
|
<td>{user.email}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{$t('subscription.subscription')}</th>
|
||||||
|
<td>{user.membership?.subscription_model?.name}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{$t('status')}</th>
|
||||||
|
<td>{$t('userStatus.' + user.status)}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="button-group">
|
||||||
|
<button class="btn primary" on:click={() => openEditUserModal(user)}>
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
{$t('edit')}
|
||||||
|
</button>
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="?/userDelete"
|
||||||
|
use:enhance={() => {
|
||||||
|
return async ({ result }) => {
|
||||||
|
if (result.type === 'success' || result.type === 'redirect') {
|
||||||
|
await applyAction(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
on:submit|preventDefault={(/** @type {SubmitEvent} */ e) => {
|
||||||
|
if (
|
||||||
|
!confirm(
|
||||||
|
$t('dialog.user_deletion', {
|
||||||
|
values: {
|
||||||
|
firstname: user.first_name || '',
|
||||||
|
lastname: user.last_name || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
e.preventDefault(); // Cancel form submission if user declines
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input type="hidden" name="user[id]" value={user.id} />
|
||||||
|
<input type="hidden" name="user[last_name]" value={user.last_name} />
|
||||||
|
<button class="btn danger" type="submit">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
{$t('delete')}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else if activeSection === 'supporter'}
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>{$t('supporter')}</h2>
|
||||||
|
<div class="title-container">
|
||||||
|
<InputField
|
||||||
|
name="search"
|
||||||
|
bind:value={searchTerm}
|
||||||
|
placeholder={$t('placeholder.search')}
|
||||||
|
backgroundColor="--base"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="btn primary"
|
||||||
|
aria-label="Mail Supporter"
|
||||||
|
on:click={() => handleMailButtonClick(filteredSupporters)}
|
||||||
|
>
|
||||||
|
<i class="fas fa-envelope"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn primary" on:click={() => openEditUserModal(null)}>
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
{$t('add_new')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion">
|
||||||
|
{#each filteredSupporters as user}
|
||||||
<details class="accordion-item">
|
<details class="accordion-item">
|
||||||
<summary class="accordion-header">
|
<summary class="accordion-header">
|
||||||
{user.first_name}
|
{user.first_name}
|
||||||
@@ -272,7 +397,7 @@
|
|||||||
{:else if activeSection === 'subscriptions'}
|
{:else if activeSection === 'subscriptions'}
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>{$t('subscription.subscriptions')}</h2>
|
<h2>{$t('subscription.subscriptions')}</h2>
|
||||||
{#if user.role_id == 8}
|
{#if hasPrivilige(user, PERMISSIONS.Super)}
|
||||||
<button class="btn primary" on:click={() => openEditSubscriptionModal(null)}>
|
<button class="btn primary" on:click={() => openEditSubscriptionModal(null)}>
|
||||||
<i class="fas fa-plus"></i>
|
<i class="fas fa-plus"></i>
|
||||||
{$t('add_new')}
|
{$t('add_new')}
|
||||||
@@ -285,7 +410,7 @@
|
|||||||
<summary class="accordion-header">
|
<summary class="accordion-header">
|
||||||
{subscription.name}
|
{subscription.name}
|
||||||
<span class="nav-badge"
|
<span class="nav-badge"
|
||||||
>{users.filter(
|
>{members.filter(
|
||||||
(/** @type{App.Locals['user']}*/ user) =>
|
(/** @type{App.Locals['user']}*/ user) =>
|
||||||
user.membership?.subscription_model?.name === subscription.name
|
user.membership?.subscription_model?.name === subscription.name
|
||||||
).length}</span
|
).length}</span
|
||||||
@@ -328,7 +453,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{#if user.role_id == 8}
|
{#if hasPrivilige(user, PERMISSIONS.Super)}
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<button
|
<button
|
||||||
class="btn primary"
|
class="btn primary"
|
||||||
@@ -337,7 +462,7 @@
|
|||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
{$t('edit')}
|
{$t('edit')}
|
||||||
</button>
|
</button>
|
||||||
{#if !users.some(/** @param{App.Locals['user']} user */ (user) => user.membership?.subscription_model?.id === subscription.id)}
|
{#if !members.some(/** @param{App.Locals['user']} user */ (user) => user.membership?.subscription_model?.id === subscription.id)}
|
||||||
<form
|
<form
|
||||||
method="POST"
|
method="POST"
|
||||||
action="?/subscriptionDelete"
|
action="?/subscriptionDelete"
|
||||||
@@ -415,7 +540,7 @@
|
|||||||
<Modal on:close={close}>
|
<Modal on:close={close}>
|
||||||
<UserEditForm
|
<UserEditForm
|
||||||
{form}
|
{form}
|
||||||
role_id={user.role_id}
|
editor={user}
|
||||||
user={selectedUser}
|
user={selectedUser}
|
||||||
{subscriptions}
|
{subscriptions}
|
||||||
{licence_categories}
|
{licence_categories}
|
||||||
|
|||||||
@@ -66,22 +66,24 @@ var Priviliges = struct {
|
|||||||
Update int8
|
Update int8
|
||||||
Delete int8
|
Delete int8
|
||||||
}{
|
}{
|
||||||
View: 1,
|
View: 2,
|
||||||
Update: 4,
|
Update: 4,
|
||||||
Create: 4,
|
Create: 4,
|
||||||
Delete: 4,
|
Delete: 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Roles = struct {
|
var Roles = struct {
|
||||||
Member int8
|
Supporter int8
|
||||||
Viewer int8
|
Member int8
|
||||||
Editor int8
|
Viewer int8
|
||||||
Admin int8
|
Editor int8
|
||||||
|
Admin int8
|
||||||
}{
|
}{
|
||||||
Member: 0,
|
Supporter: 0,
|
||||||
Viewer: 1,
|
Member: 1,
|
||||||
Editor: 4,
|
Viewer: 2,
|
||||||
Admin: 8,
|
Editor: 4,
|
||||||
|
Admin: 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
var MemberUpdateFields = map[string]bool{
|
var MemberUpdateFields = map[string]bool{
|
||||||
|
|||||||
Reference in New Issue
Block a user