From c9e181e8a8c13e869bc2207a5128fd4c76182387 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 31 Aug 2025 18:58:16 +0200 Subject: [PATCH] Sort member lists by last name instead of first name - Updated member-list.vue to sort by last name with new sort options - Changed default sort to lastname-asc - Added Last Name and First Name sort options in dropdown - Updated board/members/index.vue to include name field and sort by last name - Updated admin/members/index.vue to include name field and sort by last name - All member lists now consistently sort alphabetically by last name --- pages/admin/members/index.vue | 17 +++++++++++++++++ pages/board/members/index.vue | 20 +++++++++++++++++++- pages/dashboard/member-list.vue | 28 +++++++++++++++++++++------- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/pages/admin/members/index.vue b/pages/admin/members/index.vue index 6dc585b..8888dbe 100644 --- a/pages/admin/members/index.vue +++ b/pages/admin/members/index.vue @@ -475,6 +475,8 @@ const loadMembers = async () => { member_id: member.Id || member.id, first_name: member.first_name, last_name: member.last_name, + // Add name field for sorting (last name, first name format) + name: `${member.last_name || ''}, ${member.first_name || ''}`.trim(), email: member.email, membership_type: member.membership_type || 'Standard', status: member.membership_status === 'Active' ? 'active' : 'inactive', @@ -483,6 +485,21 @@ const loadMembers = async () => { phone: member.phone_number || member.phone || '' })); + // Sort by last name, then first name by default + members.value.sort((a, b) => { + const aLastName = (a.last_name || '').toLowerCase(); + const bLastName = (b.last_name || '').toLowerCase(); + const aFirstName = (a.first_name || '').toLowerCase(); + const bFirstName = (b.first_name || '').toLowerCase(); + + // First compare by last name + const lastNameCompare = aLastName.localeCompare(bLastName); + if (lastNameCompare !== 0) return lastNameCompare; + + // If last names are the same, compare by first name + return aFirstName.localeCompare(bFirstName); + }); + // Calculate stats from real data const now = new Date(); const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); diff --git a/pages/board/members/index.vue b/pages/board/members/index.vue index 87dec0b..aa443f8 100644 --- a/pages/board/members/index.vue +++ b/pages/board/members/index.vue @@ -410,6 +410,7 @@ const headers = [ // Real members data from API const members = ref([]); +const loading = ref(false); // New member form const newMember = ref({ @@ -538,6 +539,8 @@ const loadMembers = async () => { memberId: member.member_id || `MUSA-${String(member.Id).padStart(4, '0')}`, firstName: member.first_name, lastName: member.last_name, + // Add name field for sorting (last name, first name format for proper sorting) + name: `${member.last_name || ''}, ${member.first_name || ''}`.trim(), email: member.email, phone: member.phone_number || member.phone || '', status: member.membership_status === 'Active' ? 'Active' : 'Inactive', @@ -547,7 +550,22 @@ const loadMembers = async () => { nationality: member.nationality || member.country || '' })); - console.log(`[board-members] Loaded ${members.value.length} members from API`); + // Sort by last name, then first name by default + members.value.sort((a, b) => { + const aLastName = (a.lastName || '').toLowerCase(); + const bLastName = (b.lastName || '').toLowerCase(); + const aFirstName = (a.firstName || '').toLowerCase(); + const bFirstName = (b.firstName || '').toLowerCase(); + + // First compare by last name + const lastNameCompare = aLastName.localeCompare(bLastName); + if (lastNameCompare !== 0) return lastNameCompare; + + // If last names are the same, compare by first name + return aFirstName.localeCompare(bFirstName); + }); + + console.log(`[board-members] Loaded ${members.value.length} members from API, sorted by last name`); } } catch (error) { console.error('Error loading members:', error); diff --git a/pages/dashboard/member-list.vue b/pages/dashboard/member-list.vue index 8d90256..9fe6d36 100644 --- a/pages/dashboard/member-list.vue +++ b/pages/dashboard/member-list.vue @@ -285,7 +285,7 @@ const error = ref(''); const searchTerm = ref(''); const activeFilter = ref(''); const duesFilter = ref(''); -const sortOption = ref('name-asc'); +const sortOption = ref('lastname-asc'); // Dialogs const showAddDialog = ref(false); @@ -329,8 +329,10 @@ const duesFilterOptions = [ // Sort options const sortOptions = [ - { title: 'Name (A-Z)', value: 'name-asc' }, - { title: 'Name (Z-A)', value: 'name-desc' }, + { title: 'Last Name (A-Z)', value: 'lastname-asc' }, + { title: 'Last Name (Z-A)', value: 'lastname-desc' }, + { title: 'First Name (A-Z)', value: 'firstname-asc' }, + { title: 'First Name (Z-A)', value: 'firstname-desc' }, { title: 'Nationality (A-Z)', value: 'nationality-asc' }, { title: 'Nationality (Z-A)', value: 'nationality-desc' } ]; @@ -373,11 +375,23 @@ const filteredMembers = computed(() => { // Sorting if (sortOption.value) { filtered.sort((a, b) => { + // Extract first and last names properly + const getLastName = (member: any) => member.last_name || ''; + const getFirstName = (member: any) => member.first_name || ''; + switch (sortOption.value) { - case 'name-asc': - return (a.FullName || '').localeCompare(b.FullName || ''); - case 'name-desc': - return (b.FullName || '').localeCompare(a.FullName || ''); + case 'lastname-asc': { + const lastNameCompare = getLastName(a).localeCompare(getLastName(b)); + return lastNameCompare !== 0 ? lastNameCompare : getFirstName(a).localeCompare(getFirstName(b)); + } + case 'lastname-desc': { + const lastNameCompare = getLastName(b).localeCompare(getLastName(a)); + return lastNameCompare !== 0 ? lastNameCompare : getFirstName(b).localeCompare(getFirstName(a)); + } + case 'firstname-asc': + return getFirstName(a).localeCompare(getFirstName(b)); + case 'firstname-desc': + return getFirstName(b).localeCompare(getFirstName(a)); case 'nationality-asc': return (a.nationality || '').localeCompare(b.nationality || ''); case 'nationality-desc':