Connected DB to events/jobs + more

- Modified handlers.js to be the same as on frm.so
- Added --trash-src to shared.css
- Modified Event and Job cards to include a trash icon for deleting
- Deleting works, it just does not smoothly re-render yet
- Adjusted visual bug on Events/Jobs where the contents of the AppWindow would overflow vertically. They now scroll and the title/search bar remain fixed.
- Refactored part of People.js into PeopleCard.js
This commit is contained in:
2026-03-15 19:45:04 -04:00
parent dde27f9b31
commit 834d5e763e
9 changed files with 160 additions and 98 deletions

View File

@@ -8,11 +8,11 @@ const handlers = {
}, },
async editEvent(id, updatedEvent, networkId, userId) { async editEvent(id, updatedEvent, networkId, userId) {
return await global.db.events.add(id, updatedEvent, networkId, userId); return await global.db.events.edit(id, updatedEvent, networkId, userId);
}, },
async deleteEvent(id, networkId, userId) { async deleteEvent(id, networkId, userId) {
return await global.db.events.add(id, networkId, userId); return await global.db.events.delete(id, networkId, userId);
}, },
async getEvent(id) { async getEvent(id) {
@@ -28,11 +28,11 @@ const handlers = {
}, },
async editJob(id, updatedJob, networkId, userId) { async editJob(id, updatedJob, networkId, userId) {
return await global.db.jobs.add(id, updatedJob, networkId, userId); return await global.db.jobs.edit(id, updatedJob, networkId, userId);
}, },
async deleteJob(id, networkId, userId) { async deleteJob(id, networkId, userId) {
return await global.db.jobs.add(id, networkId, userId); return await global.db.jobs.delete(id, networkId, userId);
}, },
async getJob(id) { async getJob(id) {

View File

@@ -27,6 +27,7 @@
--column-src: /_/icons/column2.svg; --column-src: /_/icons/column2.svg;
--nodes-src: /_/icons/nodes.svg; --nodes-src: /_/icons/nodes.svg;
--forum-src: /_/icons/forum.svg; --forum-src: /_/icons/forum.svg;
--trash-src: /_/icons/trash.svg;
--pin-src: /_/icons/pin.svg; --pin-src: /_/icons/pin.svg;
--time-src: /_/icons/time.svg; --time-src: /_/icons/time.svg;
@@ -56,6 +57,7 @@
--column-src: /_/icons/column2.svg; --column-src: /_/icons/column2.svg;
--nodes-src: /_/icons/nodes.svg; --nodes-src: /_/icons/nodes.svg;
--forum-src: /_/icons/forum.svg; --forum-src: /_/icons/forum.svg;
--trash-src: /_/icons/trash.svg;
--pin-src: /_/icons/pinlight.svg; --pin-src: /_/icons/pinlight.svg;
--time-src: /_/icons/timelight.svg; --time-src: /_/icons/timelight.svg;

View File

@@ -1,4 +1,5 @@
import util from "../../util" import util from "../../util"
import server from "../../_/code/bridge/serverFunctions.js"
class EventCard extends Shadow { class EventCard extends Shadow {
constructor(event) { constructor(event) {
@@ -8,11 +9,23 @@ class EventCard extends Shadow {
render() { render() {
VStack(() => { VStack(() => {
h3(this.event.title) HStack(() => {
.color("var(--brown)") h3(this.event.title)
.fontSize(1.2, em) .color("var(--brown)")
.fontWeight("bold") .fontSize(1.2, em)
.marginVertical(0, em) .fontWeight("bold")
.marginVertical(0, em)
if (this.event.creator_id === global.profile.id) {
img(util.cssVariable("trash-src"), "1.5em")
.marginRight(0.5, em)
.onTap(() => {
this.deleteEvent(this.event)
})
}
})
.justifyContent("space-between")
.verticalAlign("center")
HStack(() => { HStack(() => {
img(util.cssVariable("pin-src"), "1.3em") img(util.cssVariable("pin-src"), "1.3em")
@@ -38,6 +51,13 @@ class EventCard extends Shadow {
.gap(0.5, em) .gap(0.5, em)
} }
async deleteEvent(event) {
const result = await server.deleteEvent(event.id, event.network_id, global.profile.id)
if (result.data === null) {
console.log("Failed to delete event")
}
}
convertDate(rawDate) { convertDate(rawDate) {
const parsed = new Date(rawDate); const parsed = new Date(rawDate);

View File

@@ -22,23 +22,9 @@ css(`
`) `)
class Events extends Shadow { class Events extends Shadow {
events = [
{
id: 1,
network_id: 2,
creator_id: 1,
title: "Austin Chapter Lead",
description: "This is the descriptio lets try a longer one agaiin just to see what it would look like? mayeb even longer bc that was pretty short now that i see it. maybe 2 sentences if possible or more.",
location: "1234 location",
time_start: "2026-01-13 13:41:41.0722",
created: "2026-01-13 12:00:00.0000",
updated_at: "2026-01-13 13:41:41.0722"
}
]
constructor() { constructor() {
super() super()
// this.events = global.currentNetwork.data.events; this.events = global.currentNetwork.data.events;
} }
render() { render() {
@@ -55,21 +41,24 @@ class Events extends Shadow {
SearchBar() SearchBar()
if (this.events == "" || this.events == []) { VStack(() => {
LoadingCircle() if (this.events == "" || this.events == []) {
} else if (this.events.length > 0) { LoadingCircle()
for (let i = 0; i < this.events.length; i++) { } else if (this.events.length > 0) {
EventCard(this.events[i]) for (let i = 0; i < this.events.length; i++) {
.borderTop(i == 0 ? "1px solid var(--divider)" : "") EventCard(this.events[i])
.borderTop(i == 0 ? "1px solid var(--divider)" : "")
}
} else {
h2("No Events")
.color("var(--brown)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
} }
} else { })
h2("No Events") .overflowY("scroll")
.color("var(--brown)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
}
}) })
.boxSizing("border-box") .boxSizing("border-box")
.paddingVertical(1, em) .paddingVertical(1, em)
@@ -79,8 +68,8 @@ class Events extends Shadow {
async getEvents(networkId) { async getEvents(networkId) {
const fetchedEvents = await server.getEvents(networkId) const fetchedEvents = await server.getEvents(networkId)
if (this.checkForUpdates(this.events, fetchedEvents)) { if (this.checkForUpdates(this.events, fetchedEvents.data)) {
this.events = fetchedEvents this.events = fetchedEvents.data
this.rerender() this.rerender()
} }
} }

View File

@@ -1,4 +1,5 @@
import util from "../../util.js" import util from "../../util.js"
import server from "../../_/code/bridge/serverFunctions.js"
class JobCard extends Shadow { class JobCard extends Shadow {
constructor(job) { constructor(job) {
@@ -8,11 +9,23 @@ class JobCard extends Shadow {
render() { render() {
VStack(() => { VStack(() => {
h3(this.job.title) HStack(() => {
.color("var(--brown)") h3(this.job.title)
.fontSize(1.2, em) .color("var(--brown)")
.fontWeight("bold") .fontSize(1.2, em)
.marginVertical(0, em) .fontWeight("bold")
.marginVertical(0, em)
if (this.job.creator_id === global.profile.id) {
img(util.cssVariable("trash-src"), "1.5em")
.marginRight(0.5, em)
.onTap(() => {
this.deleteJob(this.job)
})
}
})
.justifyContent("space-between")
.verticalAlign("center")
HStack(() => { HStack(() => {
img(util.cssVariable("pin-src"), "1.3em") img(util.cssVariable("pin-src"), "1.3em")
@@ -34,6 +47,13 @@ class JobCard extends Shadow {
.gap(0.5, em) .gap(0.5, em)
.boxSizing("border-box") .boxSizing("border-box")
} }
async deleteJob(job) {
const result = await server.deleteJob(job.id, job.network_id, global.profile.id)
if (result.data === null) {
console.log("Failed to delete job")
}
}
} }
register(JobCard) register(JobCard)

View File

@@ -24,20 +24,10 @@ css(`
`) `)
class Jobs extends Shadow { class Jobs extends Shadow {
jobs = [ constructor() {
{ super()
id: 1, this.jobs = global.currentNetwork.data.jobs;
network_id: 2, }
creator_id: 1,
title: "Austin Chapter Lead",
description: "This is the description",
salary: 50000.00,
company: "Hyperia",
location: "1234 location",
created: "2026-03-12 13:41:41.0722",
updated_at: "2026-03-12 13:41:41.0722"
}
]
render() { render() {
VStack(() => { VStack(() => {
@@ -55,21 +45,24 @@ class Jobs extends Shadow {
SearchBar() SearchBar()
if (this.jobs == "" || this.jobs == []) { VStack(() => {
LoadingCircle() if (this.jobs == "" || this.jobs == []) {
} else if (this.jobs.length > 0) { LoadingCircle()
for (let i = 0; i < this.jobs.length; i++) { } else if (this.jobs.length > 0) {
JobCard(this.jobs[i]) for (let i = 0; i < this.jobs.length; i++) {
.borderTop(i == 0 ? "1px solid var(--divider)" : "") JobCard(this.jobs[i])
.borderTop(i == 0 ? "1px solid var(--divider)" : "")
}
} else {
h2("No Jobs")
.color("var(--brown)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
} }
} else { })
h2("No Jobs") .overflowY("scroll")
.color("var(--brown)")
.fontWeight("bold")
.marginTop(7.5, em)
.marginBottom(0.5, em)
.textAlign("center")
}
}) })
.boxSizing("border-box") .boxSizing("border-box")
.paddingVertical(1, em) .paddingVertical(1, em)
@@ -79,7 +72,7 @@ class Jobs extends Shadow {
async getJobs(networkId) { async getJobs(networkId) {
const fetchedJobs = await server.getJobs(networkId) const fetchedJobs = await server.getJobs(networkId)
if (this.checkForUpdates(this.jobs, fetchedJobs)) { if (this.checkForUpdates(this.jobs, fetchedJobs.data)) {
this.jobs = fetchedJobs this.jobs = fetchedJobs
this.rerender() this.rerender()
} }

View File

@@ -1,3 +1,5 @@
import "./PeopleCard.js"
css(` css(`
people- { people- {
font-family: 'Arial'; font-family: 'Arial';
@@ -41,30 +43,7 @@ class People extends Shadow {
LoadingCircle() LoadingCircle()
} else if (this.people.length > 0) { } else if (this.people.length > 0) {
for (let i = 0; i < this.people.length; i++) { for (let i = 0; i < this.people.length; i++) {
HStack(() => { PeopleCard(this.people[i])
HStack(() => { })
.boxSizing("border-box")
.height(3.5, em)
.width(3.5, em)
.padding(0.5, em)
.border("1px solid var(--accent)")
.borderRadius(100, pct)
.background("black")
VStack(() => {
h3(this.people[i].first_name + " " + this.people[i].last_name)
.color("var(--brown)")
.fontSize(1.2, em)
.fontWeight("bold")
.marginVertical(0, em)
p("<b>Member since: </b>" + " " + this.convertDate(this.people[i].created))
})
.verticalAlign("center")
.gap(0.5, em)
})
.height(3.5, em)
.padding(0.75, em)
.gap(1, em)
} }
} else { } else {
h2("No Members") h2("No Members")

View File

@@ -0,0 +1,58 @@
class PeopleCard extends Shadow {
constructor(person) {
super()
this.person = person
}
render() {
HStack(() => {
HStack(() => { })
.boxSizing("border-box")
.height(3.5, em)
.width(3.5, em)
.padding(0.5, em)
.border("1px solid var(--accent)")
.borderRadius(100, pct)
.background("black")
VStack(() => {
h3(this.person.first_name + " " + this.person.last_name)
.color("var(--brown)")
.fontSize(1.2, em)
.fontWeight("bold")
.marginVertical(0, em)
p("<b>Member since: </b>" + " " + this.convertDate(this.person.created))
})
.verticalAlign("center")
.gap(0.5, em)
})
.height(3.5, em)
.padding(0.75, em)
.gap(1, em)
}
convertDate(rawDate) {
const parsed = new Date(rawDate);
if (isNaN(parsed.getTime())) return rawDate;
const month = parsed.toLocaleString("en-US", { month: "long", timeZone: "UTC" });
const day = parsed.getUTCDate();
const year = parsed.getUTCFullYear();
const ordinal = (n) => {
const mod100 = n % 100;
if (mod100 >= 11 && mod100 <= 13) return `${n}th`;
switch (n % 10) {
case 1: return `${n}st`;
case 2: return `${n}nd`;
case 3: return `${n}rd`;
default: return `${n}th`;
}
};
return `${month} ${ordinal(day)}, ${year}`;
}
}
register(PeopleCard)

View File

@@ -31,6 +31,7 @@ class AppWindow extends Shadow {
} }
}) })
.height(100, pct) .height(100, pct)
.overflowY("hidden")
.display("flex") .display("flex")
.position("relative") .position("relative")
.onNavigate(() => { .onNavigate(() => {