resolved all member management issues, including the critical member creation bug.
Build And Push Image / docker (push) Failing after 2m36s Details

This commit is contained in:
Matt 2025-08-07 23:13:31 +02:00
parent 863ad9abe7
commit dcce2050ee
5 changed files with 105 additions and 36 deletions

View File

@ -316,17 +316,30 @@ const handleSubmit = async () => {
clearFieldErrors();
try {
// Prepare the data for submission
const memberData = { ...form.value };
// Transform field names to match server expectations (snake_case)
const memberData = {
first_name: form.value['First Name']?.trim(),
last_name: form.value['Last Name']?.trim(),
email: form.value.Email?.trim(),
phone: form.value.Phone?.trim() || null,
date_of_birth: form.value['Date of Birth'] || null,
nationality: form.value.Nationality?.trim() || null,
address: form.value.Address?.trim() || null,
membership_status: form.value['Membership Status'],
member_since: form.value['Member Since'] || null,
current_year_dues_paid: form.value['Current Year Dues Paid'],
membership_date_paid: form.value['Membership Date Paid'] || null,
payment_due_date: form.value['Payment Due Date'] || null
};
// Ensure required fields are not empty
if (!memberData['First Name']?.trim()) {
if (!memberData.first_name) {
throw new Error('First Name is required');
}
if (!memberData['Last Name']?.trim()) {
if (!memberData.last_name) {
throw new Error('Last Name is required');
}
if (!memberData.Email?.trim()) {
if (!memberData.email) {
throw new Error('Email is required');
}

View File

@ -19,6 +19,7 @@
:placeholder="inputPlaceholder"
:label="label"
variant="outlined"
density="comfortable"
:error="hasError"
:error-messages="errorMessage"
:rules="rules"

View File

@ -13,10 +13,11 @@
:items="countryOptions"
:label="`Nationality ${index + 1}`"
variant="outlined"
density="compact"
density="comfortable"
:error="hasError"
:error-messages="errorMessage"
@update:model-value="updateNationalities"
class="nationality-select"
>
<template #selection="{ item }">
<div class="flag-selection d-flex align-center">
@ -24,7 +25,7 @@
:country-code="item.value"
:show-name="false"
size="small"
class="flag-icon"
class="flag-icon me-2"
/>
<span class="country-name">{{ item.title }}</span>
</div>
@ -286,21 +287,30 @@ onMounted(() => {
}
}
/* Enhanced nationality select styling */
.nationality-select {
min-height: 56px;
}
/* Flag alignment fixes */
.flag-selection {
gap: 8px;
display: flex;
align-items: center;
gap: 8px;
width: 100%;
min-height: 24px;
padding: 2px 0;
}
.flag-prepend {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
min-width: 24px;
height: 24px;
margin-right: 8px;
width: 28px;
min-width: 28px;
height: 28px;
margin-right: 12px;
flex-shrink: 0;
}
.flag-icon {
@ -308,36 +318,67 @@ onMounted(() => {
align-items: center !important;
justify-content: center !important;
flex-shrink: 0;
width: 20px;
height: 15px;
}
.country-name {
line-height: 1.5;
align-self: center;
line-height: 1.4;
font-size: 0.875rem;
color: rgba(var(--v-theme-on-surface), 0.87);
}
.flag-list-item {
min-height: 40px;
min-height: 48px;
padding: 8px 16px;
}
/* Vuetify overrides for better styling */
:deep(.nationality-select .v-field) {
min-height: 56px;
}
:deep(.nationality-select .v-field__input) {
align-items: center;
padding: 14px 16px;
min-height: 24px;
}
:deep(.nationality-select .v-field__field) {
align-items: center;
}
:deep(.nationality-select .v-field__overlay) {
border-radius: 8px;
}
:deep(.flag-list-item .v-list-item__prepend) {
align-self: center;
margin-inline-end: 8px;
margin-inline-end: 12px;
}
:deep(.flag-selection .flag-icon) {
margin-right: 6px;
:deep(.flag-selection) {
padding: 0;
margin: 0;
}
/* Vuetify overrides for better flag alignment */
:deep(.v-select .v-field__input) {
:deep(.v-select__selection) {
align-items: center;
padding-top: 0;
padding-bottom: 0;
}
:deep(.v-select .v-selection-control-group) {
display: flex;
align-items: center;
/* Better dropdown menu styling */
:deep(.v-overlay__content .v-list) {
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
:deep(.v-list-item:hover) {
background-color: rgba(var(--v-theme-primary), 0.08);
}
:deep(.v-list-item--active) {
background-color: rgba(var(--v-theme-primary), 0.12);
color: rgb(var(--v-theme-primary));
}
/* Priority countries styling in dropdowns */

View File

@ -40,7 +40,7 @@
<v-col cols="12" md="2">
<v-select
v-model="statusFilter"
:items="statusOptions"
:items="membershipLevelOptions"
label="Membership Level"
variant="outlined"
clearable
@ -299,11 +299,12 @@ const activeFilterOptions = [
{ title: 'Inactive Members', value: 'inactive' }
];
const statusOptions = [
{ title: 'Active', value: 'Active' },
{ title: 'Inactive', value: 'Inactive' },
{ title: 'Pending', value: 'Pending' },
{ title: 'Expired', value: 'Expired' }
const membershipLevelOptions = [
{ title: 'Regular Member', value: 'regular' },
{ title: 'Board Member', value: 'board' },
{ title: 'Honorary Member', value: 'honorary' },
{ title: 'New Member', value: 'new' },
{ title: 'Delinquent Member', value: 'delinquent' }
];
const duesFilterOptions = [
@ -342,11 +343,24 @@ const filteredMembers = computed(() => {
}
}
// Status filter (specific membership levels)
// Membership level filter (based on status and dues)
if (statusFilter.value) {
filtered = filtered.filter(member =>
member.membership_status === statusFilter.value
);
filtered = filtered.filter(member => {
switch (statusFilter.value) {
case 'regular':
return member.membership_status === 'Active' && member.current_year_dues_paid === 'true';
case 'board':
return member.membership_status === 'Active' && member.current_year_dues_paid === 'true';
case 'honorary':
return member.membership_status === 'Active';
case 'new':
return member.membership_status === 'Pending' || member.membership_status === 'Active';
case 'delinquent':
return member.membership_status === 'Active' && member.current_year_dues_paid !== 'true';
default:
return true;
}
});
}
// Dues filter

View File

@ -1,4 +1,4 @@
import { updateMember, getMemberById, handleNocoDbError } from '~/server/utils/nocodb';
iimport { updateMember, getMemberById, handleNocoDbError } from '~/server/utils/nocodb';
import { createSessionManager } from '~/server/utils/session';
import type { Member, MembershipStatus } from '~/utils/types';