frontend: admin/users page delete inserts and error handling

This commit is contained in:
Alex
2025-02-18 11:37:47 +01:00
parent 42edc70490
commit e9d6b58f20
2 changed files with 191 additions and 36 deletions

View File

@@ -65,6 +65,7 @@ export const actions = {
userDatesFromRFC3339(locals.user); userDatesFromRFC3339(locals.user);
throw redirect(303, `/auth/admin/users`); throw redirect(303, `/auth/admin/users`);
}, },
/** /**
* *
* @param request - The request object * @param request - The request object
@@ -73,7 +74,7 @@ export const actions = {
* @param locals - The local object, housing current user * @param locals - The local object, housing current user
* @returns Error data or redirects user to the home page or the previous page * @returns Error data or redirects user to the home page or the previous page
*/ */
updateSubscription: async ({ request, fetch, cookies, locals }) => { updateSubscription: async ({ request, fetch, cookies }) => {
let formData = await request.formData(); let formData = await request.formData();
const rawData = formDataToObject(formData); const rawData = formDataToObject(formData);
@@ -81,7 +82,7 @@ export const actions = {
const isCreating = !processedData.subscription.id || processedData.subscription.id === 0; const isCreating = !processedData.subscription.id || processedData.subscription.id === 0;
console.log('Is creating: ', isCreating); console.log('Is creating: ', isCreating);
const apiURL = `${BASE_API_URI}/backend/subscriptions/upsert`; const apiURL = `${BASE_API_URI}/backend/membership/subscriptions`;
/** @type {RequestInit} */ /** @type {RequestInit} */
const requestOptions = { const requestOptions = {
@@ -104,8 +105,86 @@ export const actions = {
const response = await res.json(); const response = await res.json();
console.log('Server success response:', response); console.log('Server success response:', response);
locals.user = response; throw redirect(303, `/auth/admin/users`);
userDatesFromRFC3339(locals.user); },
/**
*
* @param request - The request object
* @param fetch - Fetch object from sveltekit
* @param cookies - SvelteKit's cookie object
* @param locals - The local object, housing current user
* @returns
*/
userDelete: async ({ request, fetch, cookies }) => {
let formData = await request.formData();
const rawData = formDataToObject(formData);
const processedData = processUserFormData(rawData);
const apiURL = `${BASE_API_URI}/backend/users/delete`;
/** @type {RequestInit} */
const requestOptions = {
method: 'DELETE',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Cookie: `jwt=${cookies.get('jwt')}`
},
body: JSON.stringify(processedData)
};
const res = await fetch(apiURL, requestOptions);
if (!res.ok) {
const response = await res.json();
const errors = formatError(response.errors);
return fail(400, { errors: errors });
}
const response = await res.json();
console.log('Server success response:', response);
throw redirect(303, `/auth/admin/users`);
},
/**
*
* @param request - The request object
* @param fetch - Fetch object from sveltekit
* @param cookies - SvelteKit's cookie object
* @param locals - The local object, housing current subscription
* @returns
*/
subscriptionDelete: async ({ request, fetch, cookies }) => {
let formData = await request.formData();
const rawData = formDataToObject(formData);
const processedData = processSubscriptionFormData(rawData);
const apiURL = `${BASE_API_URI}/backend/membership/subscriptions`;
/** @type {RequestInit} */
const requestOptions = {
method: 'DELETE',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Cookie: `jwt=${cookies.get('jwt')}`
},
body: JSON.stringify(processedData)
};
const res = await fetch(apiURL, requestOptions);
if (!res.ok) {
const response = await res.json();
const errors = formatError(response.errors);
return fail(400, { errors: errors });
}
const response = await res.json();
console.log('Server success response:', response);
throw redirect(303, `/auth/admin/users`); throw redirect(303, `/auth/admin/users`);
} }
}; };

View File

@@ -4,6 +4,8 @@
import SubscriptionEditForm from '$lib/components/SubscriptionEditForm.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';
import { applyAction, enhance } from '$app/forms';
import { receive, send } from '$lib/utils/helpers';
/** @type {import('./$types').ActionData} */ /** @type {import('./$types').ActionData} */
export let form; export let form;
@@ -21,7 +23,8 @@
let selectedUser = null; let selectedUser = null;
/** @type{App.Types['subscription'] | null} */ /** @type{App.Types['subscription'] | null} */
let selectedSubscription = null; let selectedSubscription = null;
let showModal = false; let showSubscriptionModal = false;
let showUserModal = false;
/** /**
* Opens the edit modal for the selected user. * Opens the edit modal for the selected user.
@@ -29,7 +32,7 @@
*/ */
const openEditUserModal = (user) => { const openEditUserModal = (user) => {
selectedUser = user; selectedUser = user;
showModal = true; showUserModal = true;
}; };
/** /**
@@ -38,11 +41,12 @@
*/ */
const openEditSubscriptionModal = (subscription) => { const openEditSubscriptionModal = (subscription) => {
selectedSubscription = subscription; selectedSubscription = subscription;
showModal = true; showSubscriptionModal = true;
}; };
const close = () => { const close = () => {
showModal = false; showUserModal = false;
showSubscriptionModal = false;
selectedUser = null; selectedUser = null;
selectedSubscription = null; selectedSubscription = null;
if (form) { if (form) {
@@ -98,6 +102,18 @@
<!-- Main Content --> <!-- Main Content -->
<main class="main-content"> <main class="main-content">
{#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}
{#if activeSection === 'users'} {#if activeSection === 'users'}
<div class="section-header"> <div class="section-header">
<h2>{$t('users')}</h2> <h2>{$t('users')}</h2>
@@ -139,10 +155,38 @@
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
{$t('edit')} {$t('edit')}
</button> </button>
<button class="btn danger"> <form
<i class="fas fa-trash"></i> method="POST"
{$t('delete')} action="?/userDelete"
</button> 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>
</div> </div>
</details> </details>
@@ -152,7 +196,7 @@
<div class="section-header"> <div class="section-header">
<h2>{$t('subscription.subscriptions')}</h2> <h2>{$t('subscription.subscriptions')}</h2>
{#if user.role_id == 8} {#if user.role_id == 8}
<button class="btn primary" on:click={() => openEditUserModal(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')}
</button> </button>
@@ -211,10 +255,42 @@
{$t('edit')} {$t('edit')}
</button> </button>
{#if !users.some(/** @param{App.Locals['user']} user */ (user) => user.membership?.subscription_model?.id === subscription.id)} {#if !users.some(/** @param{App.Locals['user']} user */ (user) => user.membership?.subscription_model?.id === subscription.id)}
<button class="btn danger"> <form
<i class="fas fa-trash"></i> method="POST"
{$t('delete')} action="?/subscriptionDelete"
</button> use:enhance={() => {
return async ({ result }) => {
if (result.type === 'success' || result.type === 'redirect') {
await applyAction(result);
} else {
document
.querySelector('.accordion-content')
?.scrollTo({ top: 0, behavior: 'smooth' });
await applyAction(result);
}
};
}}
on:submit|preventDefault={(/** @type {SubmitEvent} */ e) => {
if (
!confirm(
$t('dialog.subscription_deletion', {
values: {
name: subscription.name || ''
}
})
)
) {
e.preventDefault(); // Cancel form submission if user declines
}
}}
>
<input type="hidden" name="subscription[id]" value={subscription.id} />
<input type="hidden" name="subscription[name]" value={subscription.name} />
<button class="btn danger" type="submit">
<i class="fas fa-trash"></i>
{$t('delete')}
</button>
</form>
{/if} {/if}
</div> </div>
{/if} {/if}
@@ -252,26 +328,26 @@
</div> </div>
</div> </div>
{#if showModal} {#if showUserModal}
<Modal on:close={close}> <Modal on:close={close}>
{#if selectedUser} <UserEditForm
<UserEditForm {form}
{form} user={selectedUser}
user={selectedUser} {subscriptions}
{subscriptions} {licence_categories}
{licence_categories} on:cancel={close}
on:cancel={close} on:close={close}
on:close={close} />
/> </Modal>
{:else if selectedSubscription} {:else if showSubscriptionModal}
<SubscriptionEditForm <Modal on:close={close}>
{form} <SubscriptionEditForm
{user} {form}
subscription={selectedSubscription} {user}
on:cancel={close} subscription={selectedSubscription}
on:close={close} on:cancel={close}
/> on:close={close}
{/if} />
</Modal> </Modal>
{/if} {/if}