|
|
|
@ -1,17 +1,9 @@ |
|
|
|
/** |
|
|
|
* EntityGrid.vue - Unified entity grid layout component |
|
|
|
* |
|
|
|
* Extracted from GiftedDialog.vue to provide a reusable grid layout |
|
|
|
* for displaying people, projects, and special entities with selection. |
|
|
|
* |
|
|
|
* @author Matthew Raymer |
|
|
|
*/ |
|
|
|
/** * EntityGrid.vue - Unified entity grid layout component * * Extracted from |
|
|
|
GiftedDialog.vue to provide a reusable grid layout * for displaying people, |
|
|
|
projects, and special entities with selection. * * @author Matthew Raymer */ |
|
|
|
<template> |
|
|
|
<!-- Quick Search --> |
|
|
|
<div |
|
|
|
id="QuickSearch" |
|
|
|
class="mb-4 flex items-center text-sm" |
|
|
|
> |
|
|
|
<div id="QuickSearch" class="mb-4 flex items-center text-sm"> |
|
|
|
<input |
|
|
|
v-model="searchTerm" |
|
|
|
type="text" |
|
|
|
@ -20,21 +12,27 @@ |
|
|
|
@input="handleSearchInput" |
|
|
|
@keydown.enter="performSearch" |
|
|
|
/> |
|
|
|
<div |
|
|
|
<div |
|
|
|
v-show="isSearching" |
|
|
|
class="border-y border-slate-400 ps-2 py-1.5 text-center text-slate-400" |
|
|
|
> |
|
|
|
<font-awesome icon="spinner" class="fa-spin-pulse leading-[1.1]"></font-awesome> |
|
|
|
<font-awesome |
|
|
|
icon="spinner" |
|
|
|
class="fa-spin-pulse leading-[1.1]" |
|
|
|
></font-awesome> |
|
|
|
</div> |
|
|
|
<button |
|
|
|
:disabled="!searchTerm" |
|
|
|
class="px-2 py-1.5 rounded-r bg-white border border-l-0 border-slate-400 text-slate-400 disabled:cursor-not-allowed" |
|
|
|
@click="clearSearch" |
|
|
|
> |
|
|
|
<font-awesome :icon="searchTerm ? 'times' : 'magnifying-glass'" class="fa-fw"></font-awesome> |
|
|
|
<font-awesome |
|
|
|
:icon="searchTerm ? 'times' : 'magnifying-glass'" |
|
|
|
class="fa-fw" |
|
|
|
></font-awesome> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<ul class="border-t border-slate-300 mb-4 max-h-[60vh] overflow-y-auto"> |
|
|
|
<!-- Special entities (You, Unnamed) for people grids --> |
|
|
|
<template v-if="entityType === 'people'"> |
|
|
|
@ -335,7 +333,7 @@ export default class EntityGrid extends Vue { |
|
|
|
handleSearchInput(): void { |
|
|
|
// Show spinner immediately when user types |
|
|
|
this.isSearching = true; |
|
|
|
|
|
|
|
|
|
|
|
// Clear existing timeout |
|
|
|
if (this.searchTimeout) { |
|
|
|
clearTimeout(this.searchTimeout); |
|
|
|
@ -360,22 +358,26 @@ export default class EntityGrid extends Vue { |
|
|
|
|
|
|
|
try { |
|
|
|
// Simulate async search (in case we need to add API calls later) |
|
|
|
await new Promise(resolve => setTimeout(resolve, 100)); |
|
|
|
await new Promise((resolve) => setTimeout(resolve, 100)); |
|
|
|
|
|
|
|
const searchLower = this.searchTerm.toLowerCase().trim(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.entityType === "people") { |
|
|
|
this.filteredEntities = (this.entities as Contact[]).filter((contact: Contact) => { |
|
|
|
const name = contact.name?.toLowerCase() || ""; |
|
|
|
const did = contact.did.toLowerCase(); |
|
|
|
return name.includes(searchLower) || did.includes(searchLower); |
|
|
|
}); |
|
|
|
this.filteredEntities = (this.entities as Contact[]).filter( |
|
|
|
(contact: Contact) => { |
|
|
|
const name = contact.name?.toLowerCase() || ""; |
|
|
|
const did = contact.did.toLowerCase(); |
|
|
|
return name.includes(searchLower) || did.includes(searchLower); |
|
|
|
}, |
|
|
|
); |
|
|
|
} else { |
|
|
|
this.filteredEntities = (this.entities as PlanData[]).filter((project: PlanData) => { |
|
|
|
const name = project.name?.toLowerCase() || ""; |
|
|
|
const handleId = project.handleId.toLowerCase(); |
|
|
|
return name.includes(searchLower) || handleId.includes(searchLower); |
|
|
|
}); |
|
|
|
this.filteredEntities = (this.entities as PlanData[]).filter( |
|
|
|
(project: PlanData) => { |
|
|
|
const name = project.name?.toLowerCase() || ""; |
|
|
|
const handleId = project.handleId.toLowerCase(); |
|
|
|
return name.includes(searchLower) || handleId.includes(searchLower); |
|
|
|
}, |
|
|
|
); |
|
|
|
} |
|
|
|
} finally { |
|
|
|
this.isSearching = false; |
|
|
|
@ -389,7 +391,7 @@ export default class EntityGrid extends Vue { |
|
|
|
this.searchTerm = ""; |
|
|
|
this.filteredEntities = []; |
|
|
|
this.isSearching = false; |
|
|
|
|
|
|
|
|
|
|
|
// Clear any pending timeout |
|
|
|
if (this.searchTimeout) { |
|
|
|
clearTimeout(this.searchTimeout); |
|
|
|
|