frontend:locale & subscription handling
This commit is contained in:
13
frontend/src/app.d.ts
vendored
13
frontend/src/app.d.ts
vendored
@@ -3,12 +3,12 @@
|
|||||||
interface Subscription {
|
interface Subscription {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
name: string | '';
|
name: string | '';
|
||||||
details?: string | '';
|
details: string | '';
|
||||||
conditions?: string | '';
|
conditions: string | '';
|
||||||
monthly_fee?: number | -1;
|
monthly_fee: number | 0;
|
||||||
hourly_rate?: number | -1;
|
hourly_rate: number | 0;
|
||||||
included_hours_per_year?: number | 0;
|
included_hours_per_year: number | 0;
|
||||||
included_hours_per_month?: number | 0;
|
included_hours_per_month: number | 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Membership {
|
interface Membership {
|
||||||
@@ -79,6 +79,7 @@ declare global {
|
|||||||
}
|
}
|
||||||
interface Types {
|
interface Types {
|
||||||
licenceCategory: LicenceCategory;
|
licenceCategory: LicenceCategory;
|
||||||
|
subscription: Subscription;
|
||||||
}
|
}
|
||||||
// interface PageData {}
|
// interface PageData {}
|
||||||
// interface Platform {}
|
// interface Platform {}
|
||||||
|
|||||||
180
frontend/src/lib/components/SubscriptionEditForm.svelte
Normal file
180
frontend/src/lib/components/SubscriptionEditForm.svelte
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<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';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
/** @type {App.Locals['user'] } */
|
||||||
|
export let user;
|
||||||
|
|
||||||
|
/** @type {App.Types['subscription'] | null} */
|
||||||
|
export let subscription;
|
||||||
|
|
||||||
|
/** @type {App.Types['subscription']} */
|
||||||
|
const blankSubscription = {
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
details: '',
|
||||||
|
conditions: '',
|
||||||
|
monthly_fee: 0,
|
||||||
|
hourly_rate: 0,
|
||||||
|
included_hours_per_year: 0,
|
||||||
|
included_hours_per_month: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (subscription !== undefined) {
|
||||||
|
subscription = subscription === null ? { ...blankSubscription } : { ...subscription };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$: isLoading = subscription === undefined || user === undefined;
|
||||||
|
let isUpdating = false;
|
||||||
|
|
||||||
|
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
|
||||||
|
const handleUpdate = async () => {
|
||||||
|
isUpdating = true;
|
||||||
|
return async ({ result }) => {
|
||||||
|
isUpdating = false;
|
||||||
|
if (result.type === 'success' || result.type === 'redirect') {
|
||||||
|
dispatch('close');
|
||||||
|
} else {
|
||||||
|
document.querySelector('.modal .container')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
await applyAction(result);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if isLoading}
|
||||||
|
<SmallLoader width={30} message={$t('loading.subscription_data')} />
|
||||||
|
{:else if user && subscription}
|
||||||
|
<form class="content" action="?/updateSubscription" method="POST" use:enhance={handleUpdate}>
|
||||||
|
<input name="usbscription[id]" type="hidden" bind:value={subscription.id} />
|
||||||
|
<h1 class="step-title" style="text-align: center;">{$t('subscritption.edit')}</h1>
|
||||||
|
{#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}
|
||||||
|
<div class="tab-content" style="display: block">
|
||||||
|
<InputField
|
||||||
|
name="subscription[name]"
|
||||||
|
label={$t('subscription.name')}
|
||||||
|
bind:value={subscription.name}
|
||||||
|
placeholder={$t('placeholder.subscription_name')}
|
||||||
|
required={true}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="subscription[details]"
|
||||||
|
label={$t('details')}
|
||||||
|
type="textarea"
|
||||||
|
bind:value={subscription.details}
|
||||||
|
placeholder={$t('placeholder.subscription_details')}
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="subscription[conditions]"
|
||||||
|
type="textarea"
|
||||||
|
label={$t('subscription.conditions')}
|
||||||
|
bind:value={subscription.conditions}
|
||||||
|
placeholder={$t('placeholder.subscription_conditions')}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="subscription[monthly_fee]"
|
||||||
|
type="number"
|
||||||
|
label={$t('subscription.monthly_fee')}
|
||||||
|
bind:value={subscription.monthly_fee}
|
||||||
|
placeholder={$t('placeholder.subscription_monthly_fee')}
|
||||||
|
required={true}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="subscription[hourly_rate]"
|
||||||
|
type="number"
|
||||||
|
label={$t('subscription.hourly_rate')}
|
||||||
|
bind:value={subscription.hourly_rate}
|
||||||
|
required={true}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="subscription[included_hours_per_year]"
|
||||||
|
type="number"
|
||||||
|
label={$t('subscription.included_hours_per_year')}
|
||||||
|
bind:value={subscription.included_hours_per_year}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="included_hours_per_month"
|
||||||
|
type="number"
|
||||||
|
label={$t('subscription.included_hours_per_month')}
|
||||||
|
bind:value={subscription.included_hours_per_month}
|
||||||
|
readonly={user.role_id < 8}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
.tab-content {
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
background-color: var(--surface0);
|
||||||
|
border: 1px solid var(--surface1);
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container button {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 120px;
|
||||||
|
max-width: calc(50% - 5px);
|
||||||
|
background-color: var(--surface1);
|
||||||
|
color: var(--text);
|
||||||
|
border: 1px solid var(--overlay0);
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container button:hover {
|
||||||
|
background-color: var(--surface2);
|
||||||
|
border-color: var(--lavender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.button-container button {
|
||||||
|
flex-basis: 100%;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -38,7 +38,13 @@
|
|||||||
parent_member_id: 0,
|
parent_member_id: 0,
|
||||||
subscription_model: {
|
subscription_model: {
|
||||||
id: 0,
|
id: 0,
|
||||||
name: ''
|
name: '',
|
||||||
|
details: '',
|
||||||
|
conditions: '',
|
||||||
|
monthly_fee: 0,
|
||||||
|
hourly_rate: 0,
|
||||||
|
included_hours_per_month: 0,
|
||||||
|
included_hours_per_year: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
licence: {
|
licence: {
|
||||||
@@ -278,7 +284,7 @@
|
|||||||
<InputField
|
<InputField
|
||||||
name="user[email]"
|
name="user[email]"
|
||||||
type="email"
|
type="email"
|
||||||
label={$t('email')}
|
label={$t('user.email')}
|
||||||
bind:value={localUser.email}
|
bind:value={localUser.email}
|
||||||
placeholder={$t('placeholder.email')}
|
placeholder={$t('placeholder.email')}
|
||||||
required={true}
|
required={true}
|
||||||
@@ -403,29 +409,29 @@
|
|||||||
<InputField
|
<InputField
|
||||||
name="user[membership][subscription_model][name]"
|
name="user[membership][subscription_model][name]"
|
||||||
type="select"
|
type="select"
|
||||||
label={$t('subscription_model')}
|
label={$t('subscription.subscription')}
|
||||||
bind:value={localUser.membership.subscription_model.name}
|
bind:value={localUser.membership.subscription_model.name}
|
||||||
options={subscriptionModelOptions}
|
options={subscriptionModelOptions}
|
||||||
/>
|
/>
|
||||||
<div class="subscription-info">
|
<div class="subscription-info">
|
||||||
<div class="subscription-column">
|
<div class="subscription-column">
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('monthly_fee')}:</strong>
|
<strong>{$t('subscription.monthly_fee')}:</strong>
|
||||||
{selectedSubscriptionModel?.monthly_fee || '-'} €
|
{selectedSubscriptionModel?.monthly_fee || '-'} €
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('hourly_rate')}:</strong>
|
<strong>{$t('subscription.hourly_rate')}:</strong>
|
||||||
{selectedSubscriptionModel?.hourly_rate || '-'} €
|
{selectedSubscriptionModel?.hourly_rate || '-'} €
|
||||||
</p>
|
</p>
|
||||||
{#if selectedSubscriptionModel?.included_hours_per_year}
|
{#if selectedSubscriptionModel?.included_hours_per_year}
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('included_hours_per_year')}:</strong>
|
<strong>{$t('subscription.included_hours_per_year')}:</strong>
|
||||||
{selectedSubscriptionModel?.included_hours_per_year}
|
{selectedSubscriptionModel?.included_hours_per_year}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
{#if selectedSubscriptionModel?.included_hours_per_month}
|
{#if selectedSubscriptionModel?.included_hours_per_month}
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('included_hours_per_month')}:</strong>
|
<strong>{$t('subscription.included_hours_per_month')}:</strong>
|
||||||
{selectedSubscriptionModel?.included_hours_per_month}
|
{selectedSubscriptionModel?.included_hours_per_month}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -437,7 +443,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{#if selectedSubscriptionModel?.conditions}
|
{#if selectedSubscriptionModel?.conditions}
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('conditions')}:</strong>
|
<strong>{$t('subscription.conditions')}:</strong>
|
||||||
{selectedSubscriptionModel?.conditions}
|
{selectedSubscriptionModel?.conditions}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ export default {
|
|||||||
licence_number: 'Auf dem Führerschein unter Feld 5',
|
licence_number: 'Auf dem Führerschein unter Feld 5',
|
||||||
issued_date: 'Ausgabedatum unter Feld 4a',
|
issued_date: 'Ausgabedatum unter Feld 4a',
|
||||||
expiration_date: 'Ablaufdatum unter Feld 4b',
|
expiration_date: 'Ablaufdatum unter Feld 4b',
|
||||||
issuing_country: 'Ausstellendes Land'
|
issuing_country: 'Ausstellendes Land',
|
||||||
|
subscription_name: 'Name des Tarifmodells',
|
||||||
|
subscription_details: 'Beschreibe das Tarifmodell...',
|
||||||
|
subscription_conditions: 'Beschreibe die Bedingungen zur Nutzung...'
|
||||||
},
|
},
|
||||||
validation: {
|
validation: {
|
||||||
required: 'Eingabe benötigt',
|
required: 'Eingabe benötigt',
|
||||||
@@ -107,6 +110,21 @@ export default {
|
|||||||
status: 'Status',
|
status: 'Status',
|
||||||
role: 'Nutzerrolle'
|
role: 'Nutzerrolle'
|
||||||
},
|
},
|
||||||
|
subscription: {
|
||||||
|
name: 'Modellname',
|
||||||
|
edit: 'Modell bearbeiten',
|
||||||
|
subscription: 'Tarifmodell',
|
||||||
|
subscriptions: 'Tarifmodelle',
|
||||||
|
conditions: 'Bedingungen',
|
||||||
|
monthly_fee: 'Monatliche Gebühr',
|
||||||
|
hourly_rate: 'Stundensatz',
|
||||||
|
included_hours_per_year: 'Inkludierte Stunden pro Jahr',
|
||||||
|
included_hours_per_month: 'Inkludierte Stunden pro Monat'
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
user_data: 'Lade Nutzerdaten',
|
||||||
|
subscription_data: 'Lade Modelldaten'
|
||||||
|
},
|
||||||
cancel: 'Abbrechen',
|
cancel: 'Abbrechen',
|
||||||
confirm: 'Bestätigen',
|
confirm: 'Bestätigen',
|
||||||
actions: 'Aktionen',
|
actions: 'Aktionen',
|
||||||
@@ -120,10 +138,7 @@ export default {
|
|||||||
issued_date: 'Ausgabedatum',
|
issued_date: 'Ausgabedatum',
|
||||||
expiration_date: 'Ablaufdatum',
|
expiration_date: 'Ablaufdatum',
|
||||||
country: 'Land',
|
country: 'Land',
|
||||||
monthly_fee: 'Monatliche Gebühr',
|
|
||||||
hourly_rate: 'Stundensatz',
|
|
||||||
details: 'Details',
|
details: 'Details',
|
||||||
conditions: 'Bedingungen',
|
|
||||||
unknown: 'Unbekannt',
|
unknown: 'Unbekannt',
|
||||||
notes: 'Notizen',
|
notes: 'Notizen',
|
||||||
address: 'Straße & Hausnummer',
|
address: 'Straße & Hausnummer',
|
||||||
@@ -132,7 +147,6 @@ export default {
|
|||||||
forgot_password: 'Passwort vergessen?',
|
forgot_password: 'Passwort vergessen?',
|
||||||
password: 'Passwort',
|
password: 'Passwort',
|
||||||
password_repeat: 'Passwort wiederholen',
|
password_repeat: 'Passwort wiederholen',
|
||||||
email: 'Email',
|
|
||||||
company: 'Firma',
|
company: 'Firma',
|
||||||
login: 'Anmeldung',
|
login: 'Anmeldung',
|
||||||
profile: 'Profil',
|
profile: 'Profil',
|
||||||
@@ -140,7 +154,6 @@ export default {
|
|||||||
bankaccount: 'Kontodaten',
|
bankaccount: 'Kontodaten',
|
||||||
first_name: 'Vorname',
|
first_name: 'Vorname',
|
||||||
last_name: 'Nachname',
|
last_name: 'Nachname',
|
||||||
name: 'Name',
|
|
||||||
phone: 'Telefonnummer',
|
phone: 'Telefonnummer',
|
||||||
dateofbirth: 'Geburtstag',
|
dateofbirth: 'Geburtstag',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
@@ -152,11 +165,8 @@ export default {
|
|||||||
iban: 'IBAN',
|
iban: 'IBAN',
|
||||||
bic: 'BIC',
|
bic: 'BIC',
|
||||||
mandate_reference: 'SEPA Mandat',
|
mandate_reference: 'SEPA Mandat',
|
||||||
subscriptions: 'Tarifmodelle',
|
|
||||||
payments: 'Zahlungen',
|
payments: 'Zahlungen',
|
||||||
add_new: 'Neu',
|
add_new: 'Neu',
|
||||||
included_hours_per_year: 'Inkludierte Stunden pro Jahr',
|
|
||||||
included_hours_per_month: 'Inkludierte Stunden pro Monat',
|
|
||||||
|
|
||||||
// For payments section
|
// For payments section
|
||||||
payment: {
|
payment: {
|
||||||
|
|||||||
@@ -91,7 +91,15 @@ export function processFormData(rawData) {
|
|||||||
parent_member_id: Number(rawData.user.membership?.parent_member_id) || 0,
|
parent_member_id: Number(rawData.user.membership?.parent_member_id) || 0,
|
||||||
subscription_model: {
|
subscription_model: {
|
||||||
id: Number(rawData.user.membership?.subscription_model?.id) || 0,
|
id: Number(rawData.user.membership?.subscription_model?.id) || 0,
|
||||||
name: String(rawData.user.membership?.subscription_model?.name) || ''
|
name: String(rawData.user.membership?.subscription_model?.name) || '',
|
||||||
|
details: String(rawData.user.membership?.subscription_model?.details) || '',
|
||||||
|
conditions: String(rawData.user.membership?.subscription_model?.conditions) || '',
|
||||||
|
hourly_rate: Number(rawData.user.membership?.subscription_model?.hourly_rate) || 0,
|
||||||
|
monthly_fee: Number(rawData.user.membership?.subscription_model?.monthly_fee) || 0,
|
||||||
|
included_hours_per_month:
|
||||||
|
Number(rawData.user.membership?.subscription_model?.included_hours_per_month) || 0,
|
||||||
|
included_hours_per_year:
|
||||||
|
Number(rawData.user.membership?.subscription_model?.included_hours_per_year) || 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
/** @type {import('./$types').LayoutLoad} */
|
/** @type {import('./$types').LayoutLoad} */
|
||||||
export async function load({ fetch, url, data }) {
|
export async function load({ data }) {
|
||||||
const { users } = data;
|
|
||||||
return {
|
return {
|
||||||
users: data.users,
|
users: data.users,
|
||||||
user: data.user,
|
user: data.user
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,50 @@
|
|||||||
<script>
|
<script>
|
||||||
import Modal from '$lib/components/Modal.svelte';
|
import Modal from '$lib/components/Modal.svelte';
|
||||||
import UserEditForm from '$lib/components/UserEditForm.svelte';
|
import UserEditForm from '$lib/components/UserEditForm.svelte';
|
||||||
|
import SubscriptionEditForm from '$lib/components/SubscriptionEditForm.svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
/** @type {import('./$types').ActionData} */
|
/** @type {import('./$types').ActionData} */
|
||||||
export let form;
|
export let form;
|
||||||
|
|
||||||
$: ({ users = [], licence_categories = [], subscriptions = [], payments = [] } = $page.data);
|
$: ({
|
||||||
|
user = [],
|
||||||
|
users = [],
|
||||||
|
licence_categories = [],
|
||||||
|
subscriptions = [],
|
||||||
|
payments = []
|
||||||
|
} = $page.data);
|
||||||
|
|
||||||
let activeSection = 'users';
|
let activeSection = 'users';
|
||||||
/** @type{App.Locals['user'] | null} */
|
/** @type{App.Locals['user'] | null} */
|
||||||
let selectedUser = null;
|
let selectedUser = null;
|
||||||
|
/** @type{App.Types['subscription'] | null} */
|
||||||
|
let selectedSubscription = null;
|
||||||
let showModal = false;
|
let showModal = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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'] | null} user The user to edit.
|
||||||
*/
|
*/
|
||||||
const openEditModal = (user) => {
|
const openEditUserModal = (user) => {
|
||||||
selectedUser = user;
|
selectedUser = user;
|
||||||
console.dir(selectedUser);
|
showModal = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the edit modal for the selected subscription.
|
||||||
|
* @param {App.Types['subscription'] | null} subscription The user to edit.
|
||||||
|
*/
|
||||||
|
const openEditSubscriptionModal = (subscription) => {
|
||||||
|
selectedSubscription = subscription;
|
||||||
showModal = true;
|
showModal = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
showModal = false;
|
showModal = false;
|
||||||
selectedUser = null;
|
selectedUser = null;
|
||||||
|
selectedSubscription = null;
|
||||||
if (form) {
|
if (form) {
|
||||||
form.errors = undefined;
|
form.errors = undefined;
|
||||||
}
|
}
|
||||||
@@ -62,7 +80,7 @@
|
|||||||
on:click={() => setActiveSection('subscriptions')}
|
on:click={() => setActiveSection('subscriptions')}
|
||||||
>
|
>
|
||||||
<i class="fas fa-clipboard-list"></i>
|
<i class="fas fa-clipboard-list"></i>
|
||||||
{$t('subscriptions')}
|
{$t('subscription.subscriptions')}
|
||||||
<span class="nav-badge">{subscriptions.length}</span>
|
<span class="nav-badge">{subscriptions.length}</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@@ -83,7 +101,7 @@
|
|||||||
{#if activeSection === 'users'}
|
{#if activeSection === 'users'}
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>{$t('users')}</h2>
|
<h2>{$t('users')}</h2>
|
||||||
<button class="btn primary" on:click={() => openEditModal(null)}>
|
<button class="btn primary" on:click={() => openEditUserModal(null)}>
|
||||||
<i class="fas fa-plus"></i>
|
<i class="fas fa-plus"></i>
|
||||||
{$t('add_new')}
|
{$t('add_new')}
|
||||||
</button>
|
</button>
|
||||||
@@ -103,11 +121,11 @@
|
|||||||
<td>{user.id}</td>
|
<td>{user.id}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('name')}</th>
|
<th>{$t('user.name')}</th>
|
||||||
<td>{user.first_name} {user.last_name}</td>
|
<td>{user.first_name} {user.last_name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('email')}</th>
|
<th>{$t('user.email')}</th>
|
||||||
<td>{user.email}</td>
|
<td>{user.email}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -117,7 +135,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<button class="btn primary" on:click={() => openEditModal(user)}>
|
<button class="btn primary" on:click={() => openEditUserModal(user)}>
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
{$t('edit')}
|
{$t('edit')}
|
||||||
</button>
|
</button>
|
||||||
@@ -132,11 +150,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if activeSection === 'subscriptions'}
|
{:else if activeSection === 'subscriptions'}
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>{$t('subscriptions')}</h2>
|
<h2>{$t('subscription.subscriptions')}</h2>
|
||||||
<button class="btn primary" on:click={() => openEditModal(null)}>
|
{#if user.role_id == 8}
|
||||||
|
<button class="btn primary" on:click={() => openEditUserModal(null)}>
|
||||||
<i class="fas fa-plus"></i>
|
<i class="fas fa-plus"></i>
|
||||||
{$t('add_new')}
|
{$t('add_new')}
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion">
|
<div class="accordion">
|
||||||
{#each subscriptions as subscription}
|
{#each subscriptions as subscription}
|
||||||
@@ -148,7 +168,7 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('monthly_fee')}</th>
|
<th>{$t('subscription.monthly_fee')}</th>
|
||||||
<td
|
<td
|
||||||
>{subscription.monthly_fee !== -1
|
>{subscription.monthly_fee !== -1
|
||||||
? subscription.monthly_fee + '€'
|
? subscription.monthly_fee + '€'
|
||||||
@@ -156,7 +176,7 @@
|
|||||||
>
|
>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('hourly_rate')}</th>
|
<th>{$t('subscription.hourly_rate')}</th>
|
||||||
<td
|
<td
|
||||||
>{subscription.hourly_rate !== -1
|
>{subscription.hourly_rate !== -1
|
||||||
? subscription.hourly_rate + '€'
|
? subscription.hourly_rate + '€'
|
||||||
@@ -164,11 +184,11 @@
|
|||||||
>
|
>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('included_hours_per_year')}</th>
|
<th>{$t('subscription.included_hours_per_year')}</th>
|
||||||
<td>{subscription.included_hours_per_year || 0}</td>
|
<td>{subscription.included_hours_per_year || 0}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('included_hours_per_month')}</th>
|
<th>{$t('subscription.included_hours_per_month')}</th>
|
||||||
<td>{subscription.included_hours_per_month || 0}</td>
|
<td>{subscription.included_hours_per_month || 0}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -176,11 +196,28 @@
|
|||||||
<td>{subscription.details || '-'}</td>
|
<td>{subscription.details || '-'}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t('conditions')}</th>
|
<th>{$t('subscription.conditions')}</th>
|
||||||
<td>{subscription.conditions || '-'}</td>
|
<td>{subscription.conditions || '-'}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{#if user.role_id == 8}
|
||||||
|
<div class="button-group">
|
||||||
|
<button
|
||||||
|
class="btn primary"
|
||||||
|
on:click={() => openEditSubscriptionModal(subscription)}
|
||||||
|
>
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
{$t('edit')}
|
||||||
|
</button>
|
||||||
|
{#if !users.some(/** @param{App.Locals['user']} user */ (user) => user.membership?.subscription_model?.id === subscription.id)}
|
||||||
|
<button class="btn danger">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
{$t('delete')}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -217,6 +254,7 @@
|
|||||||
|
|
||||||
{#if showModal}
|
{#if showModal}
|
||||||
<Modal on:close={close}>
|
<Modal on:close={close}>
|
||||||
|
{#if selectedUser}
|
||||||
<UserEditForm
|
<UserEditForm
|
||||||
{form}
|
{form}
|
||||||
user={selectedUser}
|
user={selectedUser}
|
||||||
@@ -225,6 +263,15 @@
|
|||||||
on:cancel={close}
|
on:cancel={close}
|
||||||
on:close={close}
|
on:close={close}
|
||||||
/>
|
/>
|
||||||
|
{:else if selectedSubscription}
|
||||||
|
<SubscriptionEditForm
|
||||||
|
{form}
|
||||||
|
{user}
|
||||||
|
subscription={selectedSubscription}
|
||||||
|
on:cancel={close}
|
||||||
|
on:close={close}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
<!-- - Create a table or list view of all users.
|
|
||||||
- Implement a search or filter functionality.
|
|
||||||
- Add a modal component for editing user details (reuse the modal from about/[id]). -->
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
import Modal from "$lib/components/Modal.svelte";
|
|
||||||
import UserEditForm from "$lib/components/UserEditForm.svelte";
|
|
||||||
import { t } from "svelte-i18n";
|
|
||||||
|
|
||||||
import { page } from "$app/stores";
|
|
||||||
|
|
||||||
import "static/css/bootstrap.min.css";
|
|
||||||
import "static/js/bootstrapv5/bootstrap.bundle.min.js";
|
|
||||||
/** @type {import('./$types').ActionData} */
|
|
||||||
export let form;
|
|
||||||
|
|
||||||
$: ({ user, users, licence_categories, subscriptions } = $page.data);
|
|
||||||
|
|
||||||
/** @type(App.Locals['user'] | null) */
|
|
||||||
let selectedUser = null;
|
|
||||||
let showModal = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the edit modal for the selected user.
|
|
||||||
* @param {App.Locals['user']} user The user to edit.
|
|
||||||
*/
|
|
||||||
const openEditModal = (user) => {
|
|
||||||
selectedUser = user;
|
|
||||||
showModal = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the delete modal for the selected user.
|
|
||||||
* @param {App.Locals['user']} user The user to edit.
|
|
||||||
*/
|
|
||||||
const openDelete = (user) => {};
|
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
showModal = false;
|
|
||||||
selectedUser = null;
|
|
||||||
if (form) {
|
|
||||||
form.errors = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="admin-users-page">
|
|
||||||
<h1>{$t("user.management")}</h1>
|
|
||||||
|
|
||||||
<div class="search-filter" />
|
|
||||||
|
|
||||||
<table class="user-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{$t("user.id")}</th>
|
|
||||||
<th>{$t("name")}</th>
|
|
||||||
<th>{$t("email")}</th>
|
|
||||||
<th>{$t("status")}</th>
|
|
||||||
<th>{$t("actions")}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each users as user}
|
|
||||||
<tr>
|
|
||||||
<td>{user.id}</td>
|
|
||||||
<td>{user.first_name} {user.last_name}</td>
|
|
||||||
<td>{user.email}</td>
|
|
||||||
<td>{$t("userStatus." + user.status)}</td>
|
|
||||||
<td>
|
|
||||||
<button on:click={() => openEditModal(user)}>{$t("edit")}</button>
|
|
||||||
<button on:click={() => openDelete(user)}>{$t("delete")}</button>
|
|
||||||
</td>
|
|
||||||
</tr>{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="pagination" />
|
|
||||||
|
|
||||||
{#if showModal}
|
|
||||||
<Modal on:close={close}>
|
|
||||||
<UserEditForm
|
|
||||||
{form}
|
|
||||||
user={selectedUser}
|
|
||||||
{subscriptions}
|
|
||||||
{licence_categories}
|
|
||||||
on:cancel={close}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user