init
This commit is contained in:
203
people/desktop/people.js
Normal file
203
people/desktop/people.js
Normal file
@@ -0,0 +1,203 @@
|
||||
import "./DesktopPeopleToolbar.js"
|
||||
import "./DesktopPeopleTable.js"
|
||||
import "./DesktopPeopleDetail.js"
|
||||
import server from "/people/@server/index.js"
|
||||
|
||||
css(`
|
||||
people- {
|
||||
font-family: 'Arial';
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
people- select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.65em center;
|
||||
padding-right: 1.8em !important;
|
||||
}
|
||||
people- textarea {
|
||||
font-family: 'Arial';
|
||||
}
|
||||
people- input::placeholder {
|
||||
color: var(--headertext);
|
||||
opacity: 0.35;
|
||||
}
|
||||
`)
|
||||
|
||||
class People extends Shadow {
|
||||
|
||||
_people = (global.currentNetwork.data.members || []).map(p => ({ ...p, _online: this.isOnline(p) }))
|
||||
#lastUpdated;
|
||||
|
||||
selectedMemberId = null
|
||||
searchText = ""
|
||||
filterRole = ""
|
||||
filterTier = ""
|
||||
sortKey = "joined"
|
||||
sortDir = "asc"
|
||||
tableEl = null
|
||||
|
||||
get people() { return this._people }
|
||||
set people(val) {
|
||||
this._people = val
|
||||
this.#lastUpdated = Date.now()
|
||||
global.currentNetwork.data.members = val
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
isOnline(member) {
|
||||
return global.socket.connectedUsers.includes(member.email)
|
||||
}
|
||||
|
||||
get filteredSortedPeople() {
|
||||
let list = this.people;
|
||||
|
||||
if (this.searchText) {
|
||||
const q = this.searchText.toLowerCase();
|
||||
list = list.filter(p =>
|
||||
[p.first_name, p.last_name, p.email, p.title, p.county, p.city, p.state]
|
||||
.some(v => v?.toLowerCase().includes(q))
|
||||
);
|
||||
}
|
||||
|
||||
if (this.filterRole) {
|
||||
list = list.filter(p => (p.roles || []).includes(this.filterRole));
|
||||
}
|
||||
|
||||
if (this.filterTier) {
|
||||
list = list.filter(p => String(p.plan_name) === this.filterTier);
|
||||
}
|
||||
|
||||
// Sort
|
||||
const key = this.sortKey;
|
||||
const dir = this.sortDir === "asc" ? 1 : -1;
|
||||
list = [...list].sort((a, b) => {
|
||||
let av, bv;
|
||||
if (key === "name") { av = `${a.first_name} ${a.last_name}`; bv = `${b.first_name} ${b.last_name}`; }
|
||||
else if (key === "email") { av = a.email || ""; bv = b.email || ""; }
|
||||
else if (key === "title") { av = a.title || ""; bv = b.title || ""; }
|
||||
else if (key === "county") { av = a.county || ""; bv = b.county || ""; }
|
||||
else if (key === "roles") { av = (a.roles || [])[0] || ""; bv = (b.roles || [])[0] || ""; }
|
||||
else if (key === "tier") { av = a.plan_name || 0; bv = b.plan_name || 0; }
|
||||
else if (key === "joined") {
|
||||
av = new Date(a.joined_network || a.created || 0).getTime();
|
||||
bv = new Date(b.joined_network || b.created || 0).getTime();
|
||||
}
|
||||
if (typeof av === "string") return av.localeCompare(bv) * dir;
|
||||
return (av - bv) * dir;
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
get selectedMember() {
|
||||
return this.people.find(p => p.id === this.selectedMemberId) || null;
|
||||
}
|
||||
|
||||
handleSort(key) {
|
||||
if (this.sortKey === key) {
|
||||
this.sortDir = this.sortDir === "asc" ? "desc" : "asc";
|
||||
} else {
|
||||
this.sortKey = key;
|
||||
this.sortDir = "asc";
|
||||
}
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
render() {
|
||||
const filtered = this.filteredSortedPeople;
|
||||
const detailOpen = !!this.selectedMember;
|
||||
|
||||
VStack(() => {
|
||||
DesktopPeopleToolbar(
|
||||
filtered,
|
||||
this.searchText,
|
||||
this.filterRole,
|
||||
this.filterTier,
|
||||
(text) => {
|
||||
this.searchText = text
|
||||
this.tableEl.people = this.filteredSortedPeople
|
||||
this.tableEl.rerender()
|
||||
},
|
||||
(role) => { this.filterRole = role; this.rerender(); },
|
||||
(tier) => { this.filterTier = tier; this.rerender(); }
|
||||
)
|
||||
|
||||
HStack(() => {
|
||||
// Table — shrinks when drawer open
|
||||
VStack(() => {
|
||||
this.tableEl = DesktopPeopleTable(
|
||||
filtered,
|
||||
this.selectedMemberId,
|
||||
this.sortKey,
|
||||
this.sortDir,
|
||||
(id) => {
|
||||
this.selectedMemberId = this.selectedMemberId === id ? null : id;
|
||||
this.rerender();
|
||||
},
|
||||
(key) => this.handleSort(key)
|
||||
)
|
||||
})
|
||||
.flex(1).height(100, pct).overflow("hidden")
|
||||
|
||||
// Slide-out detail drawer
|
||||
if (detailOpen) {
|
||||
VStack(() => {
|
||||
// Drawer header with close button
|
||||
HStack(() => {
|
||||
p(`${this.selectedMember.first_name} ${this.selectedMember.last_name}`)
|
||||
.margin(0).fontSize(0.88, em).fontWeight("600")
|
||||
.color("var(--headertext)").flex(1).minWidth(0)
|
||||
.overflow("hidden").whiteSpace("nowrap").textOverflow("ellipsis")
|
||||
|
||||
button("✕")
|
||||
.border("none").background("transparent")
|
||||
.color("var(--headertext)").opacity(0.4)
|
||||
.fontSize(0.82, em).cursor("pointer").padding(0.25, em)
|
||||
.borderRadius(0.3, em)
|
||||
.onClick((done) => {if(!done) return; this.selectedMemberId = null; this.rerender(); })
|
||||
})
|
||||
.paddingHorizontal(1.25, em).paddingVertical(0.78, em)
|
||||
.borderBottom("1px solid var(--divider)")
|
||||
.alignItems("center").flexShrink(0)
|
||||
|
||||
VStack(() => {
|
||||
DesktopPeopleDetail(this.selectedMember,
|
||||
(updatedPerson) => this.updatePeople(updatedPerson)
|
||||
)
|
||||
})
|
||||
.flex(1).overflow("hidden")
|
||||
})
|
||||
.width(360, px)
|
||||
.height(100, pct)
|
||||
.borderLeft("1px solid var(--divider)")
|
||||
.flexShrink(0)
|
||||
.overflow("hidden")
|
||||
}
|
||||
})
|
||||
.flex(1).minHeight(0).width(100, pct).overflow("hidden")
|
||||
})
|
||||
.height(100, pct).width(100, pct).overflow("hidden")
|
||||
.onAppear(async () => {
|
||||
const res = await server.getPeople(global.currentNetwork.id);
|
||||
if (!res.error && res.length > 0) {
|
||||
if((this.people.length !== res.length) || !this.#lastUpdated) {
|
||||
this.people = res.map(p => ({ ...p, _online: this.isOnline(p) }));
|
||||
this.rerender();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updatePeople(person) {
|
||||
this.people = this.people.map(p => p.id === person.id ? person : p)
|
||||
this.rerender()
|
||||
}
|
||||
}
|
||||
|
||||
register(People)
|
||||
Reference in New Issue
Block a user