add: carEditForm
This commit is contained in:
252
frontend/src/lib/components/CarEditForm.svelte
Normal file
252
frontend/src/lib/components/CarEditForm.svelte
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<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 { hasPrivilige, receive, send } from '$lib/utils/helpers';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
import { defaultCar } from '$lib/utils/defaults';
|
||||||
|
import { PERMISSIONS } from '$lib/utils/constants';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
/** @type {import('../../routes/auth/about/[id]/$types').ActionData} */
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
/** @type {App.Locals['user'] } */
|
||||||
|
export let editor;
|
||||||
|
|
||||||
|
/** @type {App.Types['car'] | null} */
|
||||||
|
export let car;
|
||||||
|
|
||||||
|
console.log('Opening car modal with:', car);
|
||||||
|
$: car = car || { ...defaultCar() };
|
||||||
|
$: isLoading = car === undefined || editor === undefined;
|
||||||
|
let isUpdating = false;
|
||||||
|
let readonlyUser = !hasPrivilige(editor, PERMISSIONS.Update);
|
||||||
|
|
||||||
|
const TABS = ['car.car', 'insurance', 'car.damages'];
|
||||||
|
let activeTab = TABS[0];
|
||||||
|
|
||||||
|
/** @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.car_data')} />
|
||||||
|
{:else if editor && car}
|
||||||
|
<form class="content" action="?/updateCar" method="POST" use:enhance={handleUpdate}>
|
||||||
|
<input name="susbscription[id]" type="hidden" bind:value={car.id} />
|
||||||
|
<h1 class="step-title" style="text-align: center;">
|
||||||
|
{car.id ? $t('car.edit') : $t('car.create')}
|
||||||
|
</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="button-container">
|
||||||
|
{#each TABS as tab}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="button-dark"
|
||||||
|
class:active={activeTab === tab}
|
||||||
|
on:click={() => (activeTab = tab)}
|
||||||
|
>
|
||||||
|
{$t(tab)}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="tab-content" style="display: {activeTab === 'car.car' ? 'block' : 'none'}">
|
||||||
|
<InputField
|
||||||
|
name="car[name]"
|
||||||
|
label={$t('name')}
|
||||||
|
bind:value={car.name}
|
||||||
|
placeholder={$t('placeholder.car_name')}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[brand]"
|
||||||
|
label={$t('car.brand')}
|
||||||
|
bind:value={car.brand}
|
||||||
|
placeholder={$t('placeholder.car_brand')}
|
||||||
|
required={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[model]"
|
||||||
|
label={$t('car.model')}
|
||||||
|
bind:value={car.model}
|
||||||
|
placeholder={$t('placeholder.car_model')}
|
||||||
|
required={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[color]"
|
||||||
|
label={$t('color')}
|
||||||
|
bind:value={car.color}
|
||||||
|
placeholder={$t('placeholder.car_color')}
|
||||||
|
required={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[licence_plate]"
|
||||||
|
label={$t('car.licence_plate')}
|
||||||
|
bind:value={car.licence_plate}
|
||||||
|
placeholder={$t('placeholder.car_licence_plate')}
|
||||||
|
required={true}
|
||||||
|
toUpperCase={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[price]"
|
||||||
|
type="number"
|
||||||
|
label={$t('price')}
|
||||||
|
bind:value={car.price}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[rate]"
|
||||||
|
type="number"
|
||||||
|
label={$t('car.leasing_rate')}
|
||||||
|
bind:value={car.rate}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[start_date]"
|
||||||
|
type="date"
|
||||||
|
label={$t('car.start_date')}
|
||||||
|
bind:value={car.start_date}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[end_date]"
|
||||||
|
type="date"
|
||||||
|
label={$t('car.end_date')}
|
||||||
|
bind:value={car.end_date}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[notes]"
|
||||||
|
type="textarea"
|
||||||
|
label={$t('notes')}
|
||||||
|
bind:value={car.notes}
|
||||||
|
placeholder={$t('placeholder.notes', {
|
||||||
|
values: { name: car.name || car.brand + ' ' + car.model }
|
||||||
|
})}
|
||||||
|
rows={10}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content" style="display: {activeTab === 'insurance' ? 'block' : 'none'}">
|
||||||
|
{#each car.insurances as insurance}
|
||||||
|
<InputField
|
||||||
|
name="car[insurance][company]"
|
||||||
|
label={$t('company')}
|
||||||
|
bind:value={insurance.company}
|
||||||
|
placeholder={$t('placeholder.company')}
|
||||||
|
required={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[insurance][reference]"
|
||||||
|
label={$t('insurance.reference')}
|
||||||
|
bind:value={insurance.reference}
|
||||||
|
placeholder={$t('placeholder.insurance_reference')}
|
||||||
|
required={true}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[insurance][start_date]"
|
||||||
|
type="date"
|
||||||
|
label={$t('start')}
|
||||||
|
bind:value={insurance.start_date}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[insurance][end_date]"
|
||||||
|
type="date"
|
||||||
|
label={$t('end')}
|
||||||
|
bind:value={insurance.end_date}
|
||||||
|
readonly={readonlyUser}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="car[insurance][notes]"
|
||||||
|
type="textarea"
|
||||||
|
label={$t('notes')}
|
||||||
|
bind:value={insurance.notes}
|
||||||
|
placeholder={$t('placeholder.notes', {
|
||||||
|
values: { name: insurance.company || '' }
|
||||||
|
})}
|
||||||
|
rows={10}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="button-container">
|
||||||
|
{#if isUpdating}
|
||||||
|
<SmallLoader width={30} message={$t('loading.updating')} />
|
||||||
|
{: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>
|
||||||
Reference in New Issue
Block a user