Search in Events/Jobs

- SearchBar now dispatches 'jobsearch' or 'eventsearch' event whenever the user submits a search query
- Jobs/Events will then receive searchText to do general search
- Fixed bug where Jobs/Events wouldn't scroll anymore
This commit is contained in:
2026-03-18 20:11:08 -04:00
parent 2082e0c7bc
commit ede464fb0d
4 changed files with 141 additions and 38 deletions

View File

@@ -31,19 +31,36 @@ css(`
`) `)
class Events extends Shadow { class Events extends Shadow {
static searchableKeys = ['title', 'description', 'location'];
constructor() { constructor() {
super() super()
this.events = global.currentNetwork.data.events; this.events = global.currentNetwork.data.events;
this.searchedEvents = [];
this.searchText = "";
} }
render() { render() {
VStack(() => { VStack(() => {
SearchBar() SearchBar(this.searchText)
VStack(() => { VStack(() => {
if (!this.events || this.events == []) { if (!this.events || this.events == []) {
LoadingCircle() LoadingCircle()
} else if (this.searchText) {
if (this.searchedEvents.length > 0) {
for (let i = 0; i < this.searchedEvents.length; i++) {
EventCard(this.searchedEvents[i])
}
} else {
h2("Could not find any events with your search criteria.")
.color("var(--divider)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
}
} else if (this.events.length > 0) { } else if (this.events.length > 0) {
for (let i = 0; i < this.events.length; i++) { for (let i = 0; i < this.events.length; i++) {
EventCard(this.events[i]) EventCard(this.events[i])
@@ -63,6 +80,22 @@ class Events extends Shadow {
.boxSizing("border-box") .boxSizing("border-box")
.height(100, pct) .height(100, pct)
.width(100, pct) .width(100, pct)
.onEvent("eventsearch", this.onEventSearch)
}
onEventSearch = (e) => {
let searchText = e.detail.searchText.toLowerCase().trim();
if (!searchText) {
this.searchedEvents = [];
} else {
this.searchedEvents = this.events.filter(event =>
Events.searchableKeys.some(key =>
String(event[key]).toLowerCase().includes(searchText)
)
);
}
this.searchText = searchText
this.rerender()
} }
async getEvents(networkId) { async getEvents(networkId) {

View File

@@ -32,9 +32,13 @@ css(`
`) `)
class Jobs extends Shadow { class Jobs extends Shadow {
static searchableKeys = ['title', 'description', 'location', 'company', 'salary_period', 'salary_number'];
constructor() { constructor() {
super() super()
this.jobs = global.currentNetwork.data.jobs; this.jobs = global.currentNetwork.data.jobs;
this.searchedJobs = [];
this.searchText = ""; // for mainting searchText after re-render
} }
render() { render() {
@@ -42,11 +46,24 @@ class Jobs extends Shadow {
// JobForm() // JobForm()
SearchBar() SearchBar(this.searchText)
VStack(() => { VStack(() => {
if (!this.jobs || this.jobs == []) { if (!this.jobs || this.jobs == []) {
LoadingCircle() LoadingCircle()
} else if (this.searchText) {
if (this.searchedJobs.length > 0) {
for (let i = 0; i < this.searchedJobs.length; i++) {
JobCard(this.searchedJobs[i])
}
} else {
h2("Could not find any jobs with your search criteria.")
.color("var(--divider)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
}
} else if (this.jobs.length > 0) { } else if (this.jobs.length > 0) {
for (let i = 0; i < this.jobs.length; i++) { for (let i = 0; i < this.jobs.length; i++) {
JobCard(this.jobs[i]) JobCard(this.jobs[i])
@@ -66,6 +83,26 @@ class Jobs extends Shadow {
.boxSizing("border-box") .boxSizing("border-box")
.height(100, pct) .height(100, pct)
.width(100, pct) .width(100, pct)
.onEvent("jobsearch", this.onJobSearch)
}
onJobSearch = (e) => {
let searchText = e.detail.searchText.toLowerCase().trim();
if (!searchText) {
this.searchedJobs = [];
} else {
this.searchedJobs = this.jobs.filter(job =>
Jobs.searchableKeys.some(key => {
if (key === "salary_number" || key === "salary_period") {
return String(job["salary_number"]).toLowerCase().includes(searchText.replace(/\/.*$/, '').replace(/[,$]/g, '')) && String(job["salary_period"]).toLowerCase().includes(searchText.replace(/^[^/]*\/?/, ''));
} else {
return String(job[key]).toLowerCase().includes(searchText);
}
})
);
}
this.searchText = searchText
this.rerender()
} }
async getJobs(networkId) { async getJobs(networkId) {

View File

@@ -31,6 +31,7 @@ class AppWindow extends Shadow {
break; break;
} }
}) })
.overflowY("scroll")
.onNavigate(() => { .onNavigate(() => {
this.rerender() this.rerender()
}) })

View File

@@ -5,12 +5,18 @@ css(`
`) `)
class SearchBar extends Shadow { class SearchBar extends Shadow {
constructor(searchText) {
super()
this.searchText = searchText
}
render() { render() {
form(() => {
HStack(() => { HStack(() => {
input("Search", "80%") input("Search", "80%")
.attr({ .attr({ name: "searchText", type: "text" })
"type": "text" .attr({ value: this.searchText ? this.searchText : "" })
})
.paddingVertical(0.75, em) .paddingVertical(0.75, em)
.boxSizing("border-box") .boxSizing("border-box")
.paddingHorizontal(1, em) .paddingHorizontal(1, em)
@@ -24,12 +30,16 @@ class SearchBar extends Shadow {
.outline("none") .outline("none")
.cursor("not-allowed") .cursor("not-allowed")
.onTouch(function (start) { .onTouch(function (start) {
if(start) { if (start) {
this.style.backgroundColor = "var(--accent)" this.style.backgroundColor = "var(--accent)"
} else { } else {
this.style.backgroundColor = "var(--searchbackground)" this.style.backgroundColor = "var(--searchbackground)"
} }
}) })
// .onInput(async (e) => {
// e.preventDefault();
// console.log("helloooo submitted")
// }) // can be used for live updating
p("+") p("+")
.fontWeight("bolder") .fontWeight("bolder")
@@ -46,6 +56,28 @@ class SearchBar extends Shadow {
.horizontalAlign("center") .horizontalAlign("center")
.verticalAlign("center") .verticalAlign("center")
.gap(0.5, em) .gap(0.5, em)
})
.onSubmit(async (e) => {
e.preventDefault();
const data = new FormData(e.target);
this.dispatchSearchEvent(data.get("searchText"))
})
}
dispatchSearchEvent(searchText) {
const app = global.currentApp();
switch (app) {
case "Jobs":
window.dispatchEvent(new CustomEvent('jobsearch', {
detail: { searchText: searchText }
}));
break;
case "Events":
window.dispatchEvent(new CustomEvent('eventsearch', {
detail: { searchText: searchText }
}));
break;
}
} }
} }