Compare commits
3 Commits
67ef3a2fca
...
cce2866b52
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cce2866b52 | ||
|
|
3ae1ffd403 | ||
|
|
77619c42bd |
@@ -1,5 +1,4 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
|
|
||||||
const modal = (/** @type {Element} */ node, { duration = 300 } = {}) => {
|
const modal = (/** @type {Element} */ node, { duration = 300 } = {}) => {
|
||||||
const transform = getComputedStyle(node).transform;
|
const transform = getComputedStyle(node).transform;
|
||||||
|
|
||||||
@@ -19,11 +16,6 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
function closeModal() {
|
|
||||||
dispatch('close', {});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="modal-background">
|
<div class="modal-background">
|
||||||
@@ -59,42 +51,11 @@
|
|||||||
box-shadow: 0 4px 20px rgba(17, 17, 27, 0.5); /* var(--crust) with opacity */
|
box-shadow: 0 4px 20px rgba(17, 17, 27, 0.5); /* var(--crust) with opacity */
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap;
|
|
||||||
border-width: 0;
|
|
||||||
}
|
|
||||||
@media (max-width: 990px) {
|
@media (max-width: 990px) {
|
||||||
.modal {
|
.modal {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal-close {
|
|
||||||
border: none;
|
|
||||||
padding: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close svg {
|
|
||||||
display: block;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
fill: var(--blue); /* Using Catppuccin blue */
|
|
||||||
}
|
|
||||||
.modal-close:hover svg {
|
|
||||||
fill: var(--red); /* Using Catppuccin red */
|
|
||||||
transform: scale(1.2);
|
|
||||||
}
|
|
||||||
.modal .container {
|
.modal .container {
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isNewUser = user === null;
|
// $: isNewUser = user === null;
|
||||||
$: isLoading = user === undefined;
|
$: isLoading = user === undefined;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
@@ -135,7 +135,8 @@
|
|||||||
label: sub?.name ?? ''
|
label: sub?.name ?? ''
|
||||||
}));
|
}));
|
||||||
$: selectedSubscriptionModel =
|
$: selectedSubscriptionModel =
|
||||||
subscriptions.find((sub) => sub?.id === localUser.membership?.subscription_model.id) || null;
|
subscriptions.find((sub) => sub?.name === localUser.membership?.subscription_model.name) ||
|
||||||
|
null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates groups of categories depending on the first letter
|
* creates groups of categories depending on the first letter
|
||||||
@@ -146,7 +147,7 @@
|
|||||||
return Object.entries(categories)
|
return Object.entries(categories)
|
||||||
.sort((a, b) => a[1].category.localeCompare(b[1].category))
|
.sort((a, b) => a[1].category.localeCompare(b[1].category))
|
||||||
.reduce(
|
.reduce(
|
||||||
(/** @type {Object.<string, App.Locals['licence_categories']>} */ acc, [_, category]) => {
|
(/** @type {Object.<string, App.Locals['licence_categories']>} */ acc, [, category]) => {
|
||||||
const firstLetter = category.category[0];
|
const firstLetter = category.category[0];
|
||||||
if (!acc[firstLetter]) {
|
if (!acc[firstLetter]) {
|
||||||
acc[firstLetter] = [];
|
acc[firstLetter] = [];
|
||||||
@@ -167,12 +168,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
|
/** @type {import('../../routes/auth/about/[id]/$types').SubmitFunction} */
|
||||||
const handleUpdate = async ({ formData, action, cancel }) => {
|
const handleUpdate = async () => {
|
||||||
isUpdating = true;
|
isUpdating = true;
|
||||||
return async ({ result }) => {
|
return async ({ result }) => {
|
||||||
isUpdating = false;
|
isUpdating = false;
|
||||||
if (result.type === 'success' || result.type === 'redirect') {
|
if (result.type === 'success' || result.type === 'redirect') {
|
||||||
close();
|
dispatch('close');
|
||||||
} else {
|
} else {
|
||||||
document.querySelector('.modal .container')?.scrollTo({ top: 0, behavior: 'smooth' });
|
document.querySelector('.modal .container')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
@@ -371,7 +372,7 @@
|
|||||||
<div class="licence-categories">
|
<div class="licence-categories">
|
||||||
<h3>{$t('licence_categories')}</h3>
|
<h3>{$t('licence_categories')}</h3>
|
||||||
<div class="checkbox-grid">
|
<div class="checkbox-grid">
|
||||||
{#each Object.entries(groupedCategories) as [group, categories], groupIndex}
|
{#each Object.entries(groupedCategories) as [, categories], groupIndex}
|
||||||
{#if groupIndex > 0}
|
{#if groupIndex > 0}
|
||||||
<div class="category-break"></div>
|
<div class="category-break"></div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -417,11 +418,11 @@
|
|||||||
<div class="subscription-column">
|
<div class="subscription-column">
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('monthly_fee')}:</strong>
|
<strong>{$t('monthly_fee')}:</strong>
|
||||||
{selectedSubscriptionModel?.monthly_fee || '-'}
|
{selectedSubscriptionModel?.monthly_fee || '-'} €
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>{$t('hourly_rate')}:</strong>
|
<strong>{$t('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>
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ export const actions = {
|
|||||||
const rawData = formDataToObject(formData);
|
const rawData = formDataToObject(formData);
|
||||||
const processedData = processFormData(rawData);
|
const processedData = processFormData(rawData);
|
||||||
|
|
||||||
console.dir(processedData.user.membership);
|
|
||||||
const isCreating = !processedData.user.id || processedData.user.id === 0;
|
const isCreating = !processedData.user.id || processedData.user.id === 0;
|
||||||
console.log('Is updating: ', isCreating);
|
console.log('Is creating: ', isCreating);
|
||||||
console.dir(formData);
|
// console.dir(formData);
|
||||||
|
console.dir(processedData.user.membership);
|
||||||
const apiURL = `${BASE_API_URI}/backend/users/update/`;
|
const apiURL = `${BASE_API_URI}/backend/users/update/`;
|
||||||
|
|
||||||
/** @type {RequestInit} */
|
/** @type {RequestInit} */
|
||||||
|
|||||||
@@ -86,7 +86,14 @@
|
|||||||
|
|
||||||
{#if showModal}
|
{#if showModal}
|
||||||
<Modal on:close={close}>
|
<Modal on:close={close}>
|
||||||
<UserEditForm {form} {user} {subscriptions} {licence_categories} on:cancel={close} />
|
<UserEditForm
|
||||||
|
{form}
|
||||||
|
{user}
|
||||||
|
{subscriptions}
|
||||||
|
{licence_categories}
|
||||||
|
on:close={close}
|
||||||
|
on:cancel={close}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { fail, redirect } from '@sveltejs/kit';
|
|||||||
import { formDataToObject, processFormData } from '$lib/utils/processing';
|
import { formDataToObject, processFormData } from '$lib/utils/processing';
|
||||||
|
|
||||||
/** @type {import('./$types').PageServerLoad} */
|
/** @type {import('./$types').PageServerLoad} */
|
||||||
export async function load({ locals, params }) {
|
export async function load({ locals }) {
|
||||||
// redirect user if not logged in
|
// redirect user if not logged in
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
throw redirect(302, `/auth/login?next=/auth/users`);
|
throw redirect(302, `/auth/login?next=/auth/users`);
|
||||||
|
|||||||
@@ -7,13 +7,7 @@
|
|||||||
/** @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} */
|
||||||
|
|||||||
@@ -84,14 +84,6 @@ func (uc *UserController) UpdateHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate subscription model
|
|
||||||
selectedModel, err := uc.MembershipService.GetModelByName(&user.Membership.SubscriptionModel.Name)
|
|
||||||
if err != nil {
|
|
||||||
utils.RespondWithError(c, err, "Error in UpdateHandler", http.StatusNotFound, "subscription_model", "server.validation.subscription_model_not_found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
user.Membership.SubscriptionModel = *selectedModel
|
|
||||||
|
|
||||||
updatedUser, err := uc.Service.UpdateUser(&user)
|
updatedUser, err := uc.Service.UpdateUser(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.HandleUpdateError(c, err)
|
utils.HandleUpdateError(c, err)
|
||||||
|
|||||||
@@ -51,9 +51,11 @@ func (ur *UserRepository) UpdateUser(user *models.User) (*models.User, error) {
|
|||||||
err := database.DB.Transaction(func(tx *gorm.DB) error {
|
err := database.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
// Check if the user exists in the database
|
// Check if the user exists in the database
|
||||||
var existingUser models.User
|
var existingUser models.User
|
||||||
if err := tx.Preload("Licence").
|
|
||||||
Preload("Licence.Categories").
|
if err := tx.Preload(clause.Associations).
|
||||||
Preload("Membership").
|
Preload("Membership").
|
||||||
|
Preload("Membership.SubscriptionModel").
|
||||||
|
Preload("Licence.Categories").
|
||||||
First(&existingUser, user.ID).Error; err != nil {
|
First(&existingUser, user.ID).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -109,6 +111,7 @@ func GetUserByID(userID *uint) (*models.User, error) {
|
|||||||
var user models.User
|
var user models.User
|
||||||
result := database.DB.
|
result := database.DB.
|
||||||
Preload(clause.Associations).
|
Preload(clause.Associations).
|
||||||
|
Preload("Membership").
|
||||||
Preload("Membership.SubscriptionModel").
|
Preload("Membership.SubscriptionModel").
|
||||||
Preload("Licence.Categories").
|
Preload("Licence.Categories").
|
||||||
First(&user, userID)
|
First(&user, userID)
|
||||||
|
|||||||
@@ -41,6 +41,29 @@ func (service *UserService) UpdateUser(user *models.User) (*models.User, error)
|
|||||||
setPassword(user.Password, user)
|
setPassword(user.Password, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate subscription model
|
||||||
|
selectedModel, err := repositories.GetModelByName(&user.Membership.SubscriptionModel.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ErrSubscriptionNotFound
|
||||||
|
}
|
||||||
|
user.Membership.SubscriptionModel = *selectedModel
|
||||||
|
user.Membership.SubscriptionModelID = selectedModel.ID
|
||||||
|
|
||||||
|
existingUser, err := service.GetUserByID(user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Membership.ID = existingUser.Membership.ID
|
||||||
|
|
||||||
|
user.MembershipID = existingUser.MembershipID
|
||||||
|
if existingUser.Licence != nil {
|
||||||
|
user.Licence.ID = existingUser.Licence.ID
|
||||||
|
}
|
||||||
|
user.LicenceID = existingUser.LicenceID
|
||||||
|
user.BankAccount.ID = existingUser.BankAccount.ID
|
||||||
|
user.BankAccountID = existingUser.BankAccountID
|
||||||
|
|
||||||
// if user.Licence.Status == 0 {
|
// if user.Licence.Status == 0 {
|
||||||
// // This is a new drivers licence
|
// // This is a new drivers licence
|
||||||
// user.Licence.Status = constants.UnverifiedStatus
|
// user.Licence.Status = constants.UnverifiedStatus
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ func HandleUpdateError(c *gin.Context, err error) {
|
|||||||
RespondWithError(c, err, "Error while updating user", http.StatusNotFound, "user", "server.validation.user_not_found")
|
RespondWithError(c, err, "Error while updating user", http.StatusNotFound, "user", "server.validation.user_not_found")
|
||||||
case errors.ErrInvalidUserData:
|
case errors.ErrInvalidUserData:
|
||||||
RespondWithError(c, err, "Error while updating user", http.StatusBadRequest, "user", "server.validation.invalid_user_data")
|
RespondWithError(c, err, "Error while updating user", http.StatusBadRequest, "user", "server.validation.invalid_user_data")
|
||||||
|
case errors.ErrSubscriptionNotFound:
|
||||||
|
RespondWithError(c, err, "Error while updating user", http.StatusBadRequest, "subscription", "server.validation.subscription_data")
|
||||||
default:
|
default:
|
||||||
RespondWithError(c, err, "Error while updating user", http.StatusInternalServerError, "user", "server.error.internal_server_error")
|
RespondWithError(c, err, "Error while updating user", http.StatusInternalServerError, "user", "server.error.internal_server_error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ func validateMembership(sl validator.StructLevel) {
|
|||||||
switch membership.SubscriptionModel.RequiredMembershipField {
|
switch membership.SubscriptionModel.RequiredMembershipField {
|
||||||
case "ParentMembershipID":
|
case "ParentMembershipID":
|
||||||
if err := CheckParentMembershipID(membership); err != nil {
|
if err := CheckParentMembershipID(membership); err != nil {
|
||||||
logger.Error.Printf(err.Error())
|
logger.Error.Printf("Error ParentMembershipValidation: %v", err.Error())
|
||||||
sl.ReportError(membership.ParentMembershipID, membership.SubscriptionModel.RequiredMembershipField,
|
sl.ReportError(membership.ParentMembershipID, membership.SubscriptionModel.RequiredMembershipField,
|
||||||
"RequiredMembershipField", "invalid", "")
|
"RequiredMembershipField", "invalid", "")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logger.Error.Printf(errors.ErrInvalidValue.Error())
|
logger.Error.Printf("Error no matching RequiredMembershipField: %v", errors.ErrInvalidValue.Error())
|
||||||
sl.ReportError(membership.ParentMembershipID, membership.SubscriptionModel.RequiredMembershipField,
|
sl.ReportError(membership.ParentMembershipID, membership.SubscriptionModel.RequiredMembershipField,
|
||||||
"RequiredMembershipField", "not_implemented", "")
|
"RequiredMembershipField", "not_implemented", "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func validateUser(sl validator.StructLevel) {
|
|||||||
sl.ReportError(user.DateOfBirth, "DateOfBirth", "dateofbirth", "age", "")
|
sl.ReportError(user.DateOfBirth, "DateOfBirth", "dateofbirth", "age", "")
|
||||||
}
|
}
|
||||||
// validate subscriptionModel
|
// validate subscriptionModel
|
||||||
logger.Error.Printf("User: %#v", user)
|
logger.Error.Printf("User SubscriptionModel.Name: %#v", user.Membership.SubscriptionModel.Name)
|
||||||
if user.Membership.SubscriptionModel.Name == "" {
|
if user.Membership.SubscriptionModel.Name == "" {
|
||||||
sl.ReportError(user.Membership.SubscriptionModel.Name, "SubscriptionModel.Name", "name", "required", "")
|
sl.ReportError(user.Membership.SubscriptionModel.Name, "SubscriptionModel.Name", "name", "required", "")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ var (
|
|||||||
ErrNotAuthorized = errors.New("not authorized")
|
ErrNotAuthorized = errors.New("not authorized")
|
||||||
ValErrParentIDNotSet = errors.New("Parent Membership ID not provided")
|
ValErrParentIDNotSet = errors.New("Parent Membership ID not provided")
|
||||||
ValErrParentIDNotFound = errors.New("Parent Membership ID not found")
|
ValErrParentIDNotFound = errors.New("Parent Membership ID not found")
|
||||||
|
ErrSubscriptionNotFound = errors.New("Subscription Model not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
var Responses = struct {
|
var Responses = struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user