forked from jsnbuchanan/crowd-funder-for-time-pwa
feat(EntityGrid): Split contacts into recent and alphabetical sections
When displaying contacts (not search results), show the 3 most recently added contacts at the top with a "Recently Added" heading, followed by the rest sorted alphabetically with an "Everyone Else" heading. - Add recentContacts and alphabeticalContacts computed properties - Hide "You" and "Unnamed" special entities during search - Only show search spinner when actively searching with a term - Style section headings with uppercase, improved spacing, and borders
This commit is contained in:
@@ -13,7 +13,7 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
@keydown.enter="performSearch"
|
@keydown.enter="performSearch"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-show="isSearching"
|
v-show="isSearching && searchTerm"
|
||||||
class="border-y border-slate-400 ps-2 py-1.5 text-center text-slate-400"
|
class="border-y border-slate-400 ps-2 py-1.5 text-center text-slate-400"
|
||||||
>
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
@@ -47,7 +47,7 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
<template v-if="entityType === 'people'">
|
<template v-if="entityType === 'people'">
|
||||||
<!-- "You" entity -->
|
<!-- "You" entity -->
|
||||||
<SpecialEntityCard
|
<SpecialEntityCard
|
||||||
v-if="showYouEntity"
|
v-if="showYouEntity && !searchTerm.trim()"
|
||||||
entity-type="you"
|
entity-type="you"
|
||||||
label="You"
|
label="You"
|
||||||
icon="hand"
|
icon="hand"
|
||||||
@@ -61,7 +61,7 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
|
|
||||||
<!-- "Unnamed" entity -->
|
<!-- "Unnamed" entity -->
|
||||||
<SpecialEntityCard
|
<SpecialEntityCard
|
||||||
v-if="showUnnamedEntity"
|
v-if="showUnnamedEntity && !searchTerm.trim()"
|
||||||
entity-type="unnamed"
|
entity-type="unnamed"
|
||||||
:label="unnamedEntityName"
|
:label="unnamedEntityName"
|
||||||
icon="circle-question"
|
icon="circle-question"
|
||||||
@@ -79,6 +79,49 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
|
|
||||||
<!-- Entity cards (people or projects) -->
|
<!-- Entity cards (people or projects) -->
|
||||||
<template v-if="entityType === 'people'">
|
<template v-if="entityType === 'people'">
|
||||||
|
<!-- When showing contacts without search: split into recent and alphabetical -->
|
||||||
|
<template v-if="!searchTerm.trim()">
|
||||||
|
<!-- Recently Added Section -->
|
||||||
|
<template v-if="recentContacts.length > 0">
|
||||||
|
<li
|
||||||
|
class="text-xs font-semibold text-slate-500 uppercase pt-5 pb-1.5 px-2 border-b border-slate-300"
|
||||||
|
>
|
||||||
|
Recently Added
|
||||||
|
</li>
|
||||||
|
<PersonCard
|
||||||
|
v-for="person in recentContacts"
|
||||||
|
:key="person.did"
|
||||||
|
:person="person"
|
||||||
|
:conflicted="isPersonConflicted(person.did)"
|
||||||
|
:show-time-icon="true"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
|
@person-selected="handlePersonSelected"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Alphabetical Section -->
|
||||||
|
<template v-if="alphabeticalContacts.length > 0">
|
||||||
|
<li
|
||||||
|
class="text-xs font-semibold text-slate-500 uppercase pt-5 pb-1.5 px-2 border-b border-slate-300"
|
||||||
|
>
|
||||||
|
Everyone Else
|
||||||
|
</li>
|
||||||
|
<PersonCard
|
||||||
|
v-for="person in alphabeticalContacts"
|
||||||
|
:key="person.did"
|
||||||
|
:person="person"
|
||||||
|
:conflicted="isPersonConflicted(person.did)"
|
||||||
|
:show-time-icon="true"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
|
@person-selected="handlePersonSelected"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- When searching: show filtered results normally -->
|
||||||
|
<template v-else>
|
||||||
<PersonCard
|
<PersonCard
|
||||||
v-for="person in displayedEntities as Contact[]"
|
v-for="person in displayedEntities as Contact[]"
|
||||||
:key="person.did"
|
:key="person.did"
|
||||||
@@ -90,6 +133,7 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
@person-selected="handlePersonSelected"
|
@person-selected="handlePersonSelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-else-if="entityType === 'projects'">
|
<template v-else-if="entityType === 'projects'">
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
@@ -257,6 +301,35 @@ export default class EntityGrid extends Vue {
|
|||||||
return this.entities.slice(0, maxDisplay);
|
return this.entities.slice(0, maxDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the 3 most recently added contacts (when showing contacts and not searching)
|
||||||
|
*/
|
||||||
|
get recentContacts(): Contact[] {
|
||||||
|
if (this.entityType !== "people" || this.searchTerm.trim()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// Entities are already sorted by date added (newest first)
|
||||||
|
return (this.entities as Contact[]).slice(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the remaining contacts sorted alphabetically (when showing contacts and not searching)
|
||||||
|
*/
|
||||||
|
get alphabeticalContacts(): Contact[] {
|
||||||
|
if (this.entityType !== "people" || this.searchTerm.trim()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// Skip the first 3 (recent contacts) and sort the rest alphabetically
|
||||||
|
// Create a copy to avoid mutating the original array
|
||||||
|
const remaining = (this.entities as Contact[]).slice(3);
|
||||||
|
return [...remaining].sort((a: Contact, b: Contact) => {
|
||||||
|
// Sort alphabetically by name, falling back to DID if name is missing
|
||||||
|
const nameA = (a.name || a.did).toLowerCase();
|
||||||
|
const nameB = (b.name || b.did).toLowerCase();
|
||||||
|
return nameA.localeCompare(nameB);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed empty state message based on entity type
|
* Computed empty state message based on entity type
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user