new announcements page, adding searchbar and message input.
This commit is contained in:
@@ -16,6 +16,7 @@ def capacitor_pods
|
|||||||
pod 'CapacitorGoogleMaps', :path => '../../node_modules/@capacitor/google-maps'
|
pod 'CapacitorGoogleMaps', :path => '../../node_modules/@capacitor/google-maps'
|
||||||
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
|
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
|
||||||
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
||||||
|
pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
|
||||||
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ PODS:
|
|||||||
- Capacitor
|
- Capacitor
|
||||||
- CapacitorPreferences (7.0.4):
|
- CapacitorPreferences (7.0.4):
|
||||||
- Capacitor
|
- Capacitor
|
||||||
|
- CapacitorPushNotifications (7.0.6):
|
||||||
|
- Capacitor
|
||||||
- CapacitorSplashScreen (7.0.3):
|
- CapacitorSplashScreen (7.0.3):
|
||||||
- Capacitor
|
- Capacitor
|
||||||
- Google-Maps-iOS-Utils (5.0.0):
|
- Google-Maps-iOS-Utils (5.0.0):
|
||||||
@@ -34,6 +36,7 @@ DEPENDENCIES:
|
|||||||
- "CapacitorGoogleMaps (from `../../node_modules/@capacitor/google-maps`)"
|
- "CapacitorGoogleMaps (from `../../node_modules/@capacitor/google-maps`)"
|
||||||
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
|
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
|
||||||
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
|
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
|
||||||
|
- "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)"
|
||||||
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
|
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
@@ -57,6 +60,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../../node_modules/@capacitor/haptics"
|
:path: "../../node_modules/@capacitor/haptics"
|
||||||
CapacitorPreferences:
|
CapacitorPreferences:
|
||||||
:path: "../../node_modules/@capacitor/preferences"
|
:path: "../../node_modules/@capacitor/preferences"
|
||||||
|
CapacitorPushNotifications:
|
||||||
|
:path: "../../node_modules/@capacitor/push-notifications"
|
||||||
CapacitorSplashScreen:
|
CapacitorSplashScreen:
|
||||||
:path: "../../node_modules/@capacitor/splash-screen"
|
:path: "../../node_modules/@capacitor/splash-screen"
|
||||||
|
|
||||||
@@ -68,11 +73,12 @@ SPEC CHECKSUMS:
|
|||||||
CapacitorGoogleMaps: 20b5445a532f80dbb120fa99941fd094bcc88af6
|
CapacitorGoogleMaps: 20b5445a532f80dbb120fa99941fd094bcc88af6
|
||||||
CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62
|
CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62
|
||||||
CapacitorPreferences: d82a7e3b95fcab43a553268b803356522910d153
|
CapacitorPreferences: d82a7e3b95fcab43a553268b803356522910d153
|
||||||
|
CapacitorPushNotifications: c6158ba6f3777f281a675aa43e4011e9723e822b
|
||||||
CapacitorSplashScreen: d06ae8804808e9f649a08e7bb7f283c77b688084
|
CapacitorSplashScreen: d06ae8804808e9f649a08e7bb7f283c77b688084
|
||||||
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
|
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
|
||||||
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
||||||
IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a
|
IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 4f01ce5c2aa76ddcb757b8ad50c993f40e6aeb33
|
PODFILE CHECKSUM: 7fad0e16088b635c7bc1980fea245d4a60cc4bbe
|
||||||
|
|
||||||
COCOAPODS: 1.15.2
|
COCOAPODS: 1.15.2
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@capacitor/haptics": "^7.0.3",
|
"@capacitor/haptics": "^7.0.3",
|
||||||
"@capacitor/ios": "^7.4.4",
|
"@capacitor/ios": "^7.4.4",
|
||||||
"@capacitor/preferences": "^7.0.4",
|
"@capacitor/preferences": "^7.0.4",
|
||||||
|
"@capacitor/push-notifications": "^7.0.6",
|
||||||
"@capacitor/splash-screen": "^7.0.3"
|
"@capacitor/splash-screen": "^7.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VITE_API_URL=
|
VITE_API_URL=https://frm.so
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import server from "../_/code/bridge/serverFunctions";
|
import server from "../_/code/bridge/server";
|
||||||
import util from "../util";
|
import util from "../util";
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
@@ -66,83 +66,83 @@ class Profile extends Shadow {
|
|||||||
|
|
||||||
form(() => {
|
form(() => {
|
||||||
input("Image Upload", "0px", "0px")
|
input("Image Upload", "0px", "0px")
|
||||||
.attr({ name: "image-upload", type: "file" })
|
.attr({ name: "image-upload", type: "file" })
|
||||||
.display("none")
|
.display("none")
|
||||||
.visibility("hidden")
|
.visibility("hidden")
|
||||||
.onChange((e) => {
|
.onChange((e) => {
|
||||||
this.handleUpload(e.target.files[0]);
|
this.handleUpload(e.target.files[0]);
|
||||||
})
|
})
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
if (global.profile.image_path) {
|
if (global.profile.image_path) {
|
||||||
img(`${util.HOST}${global.profile.image_path}`, "10em", "10em")
|
img(`${util.HOST}${global.profile.image_path}`, "10em", "10em")
|
||||||
.borderRadius(100, pct)
|
.borderRadius(100, pct)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.boxSizing("border-box")
|
|
||||||
.height(10, em)
|
|
||||||
.width(10, em)
|
|
||||||
.border("1px solid var(--accent)")
|
|
||||||
.borderRadius(100, pct)
|
|
||||||
.background("var(--darkaccent)")
|
|
||||||
.onTap(() => {
|
|
||||||
const inputSelector = this.$('[name="image-upload"]');
|
|
||||||
inputSelector.click()
|
|
||||||
})
|
|
||||||
|
|
||||||
p("Tap to edit")
|
|
||||||
.color("var(--headertext)")
|
|
||||||
.opacity(0.5)
|
|
||||||
.marginTop(0.5, em)
|
|
||||||
|
|
||||||
h1(this.profile.first_name + " " + this.profile.last_name)
|
|
||||||
.color("var(--headertext")
|
|
||||||
.width(70, pct)
|
|
||||||
.marginVertical(0.25, em)
|
|
||||||
.textAlign("center")
|
|
||||||
|
|
||||||
p("Joined " + this.convertDate(this.profile.created))
|
|
||||||
.color("var(--headertext)")
|
|
||||||
.marginBottom(0.5, em)
|
|
||||||
|
|
||||||
h2("Bio")
|
|
||||||
.color("var(--headertext")
|
|
||||||
.margin(0)
|
|
||||||
.paddingVertical(0.9, em)
|
|
||||||
.borderTop("2px solid var(--divider)")
|
|
||||||
.width(70, pct)
|
|
||||||
.textAlign("center")
|
|
||||||
|
|
||||||
textarea(this.bioText ? this.bioText : "Tap to start typing...")
|
|
||||||
.attr({ name: "bioinput" })
|
|
||||||
.padding(1, em)
|
|
||||||
.width(90, pct)
|
|
||||||
.height(15, em)
|
|
||||||
.boxSizing("border-box")
|
|
||||||
.background("var(--searchbackground)")
|
|
||||||
.color("var(--darktext)")
|
|
||||||
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
|
||||||
.borderRadius(12, px)
|
|
||||||
.fontFamily("Arial")
|
|
||||||
.fontSize(1.1, em)
|
|
||||||
.outline("none")
|
|
||||||
.onAppear((e) => {
|
|
||||||
if (this.bioText) {
|
|
||||||
$("profile- textarea").innerText = this.bioText
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.lineHeight(1.2, em)
|
.boxSizing("border-box")
|
||||||
|
.height(10, em)
|
||||||
|
.width(10, em)
|
||||||
|
.border("1px solid var(--accent)")
|
||||||
|
.borderRadius(100, pct)
|
||||||
|
.background("var(--darkaccent)")
|
||||||
|
.onTap(() => {
|
||||||
|
const inputSelector = this.$('[name="image-upload"]');
|
||||||
|
inputSelector.click()
|
||||||
|
})
|
||||||
|
|
||||||
|
p("Tap to edit")
|
||||||
|
.color("var(--headertext)")
|
||||||
|
.opacity(0.5)
|
||||||
|
.marginTop(0.5, em)
|
||||||
|
|
||||||
|
h1(this.profile.first_name + " " + this.profile.last_name)
|
||||||
|
.color("var(--headertext")
|
||||||
|
.width(70, pct)
|
||||||
|
.marginVertical(0.25, em)
|
||||||
|
.textAlign("center")
|
||||||
|
|
||||||
|
p("Joined " + this.convertDate(this.profile.created))
|
||||||
|
.color("var(--headertext)")
|
||||||
|
.marginBottom(0.5, em)
|
||||||
|
|
||||||
|
h2("Bio")
|
||||||
|
.color("var(--headertext")
|
||||||
|
.margin(0)
|
||||||
|
.paddingVertical(0.9, em)
|
||||||
|
.borderTop("2px solid var(--divider)")
|
||||||
|
.width(70, pct)
|
||||||
|
.textAlign("center")
|
||||||
|
|
||||||
|
textarea(this.bioText ? this.bioText : "Tap to start typing...")
|
||||||
|
.attr({ name: "bioinput" })
|
||||||
|
.padding(1, em)
|
||||||
|
.width(90, pct)
|
||||||
|
.height(15, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.color("var(--darktext)")
|
||||||
|
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
||||||
|
.borderRadius(12, px)
|
||||||
|
.fontFamily("Arial")
|
||||||
|
.fontSize(1.1, em)
|
||||||
|
.outline("none")
|
||||||
|
.onAppear((e) => {
|
||||||
|
if (this.bioText) {
|
||||||
|
$("profile- textarea").innerText = this.bioText
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.lineHeight(1.2, em)
|
||||||
|
|
||||||
button("Save Bio")
|
button("Save Bio")
|
||||||
.padding(1, em)
|
.padding(1, em)
|
||||||
.fontSize(1.1, em)
|
.fontSize(1.1, em)
|
||||||
.borderRadius(12, px)
|
.borderRadius(12, px)
|
||||||
.background("var(--searchbackground)")
|
.background("var(--searchbackground)")
|
||||||
.color("var(--text)")
|
.color("var(--text)")
|
||||||
.border("1px solid var(--accent)")
|
.border("1px solid var(--accent)")
|
||||||
.boxSizing("border-box")
|
.boxSizing("border-box")
|
||||||
.marginVertical(0.75, em)
|
.marginVertical(0.75, em)
|
||||||
})
|
})
|
||||||
.horizontalAlign("center")
|
.horizontalAlign("center")
|
||||||
.marginTop(5, em)
|
.marginTop(5, em)
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
const handlers = {
|
|
||||||
async getStripeProfile(networkId) {
|
|
||||||
return global.payments.getProfile(networkId)
|
|
||||||
},
|
|
||||||
|
|
||||||
async addEvent(newEvent, networkId, creatorId) {
|
|
||||||
try {
|
|
||||||
return await global.db.events.add(newEvent, networkId, creatorId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async editEvent(id, updatedEvent, networkId, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.events.edit(id, updatedEvent, networkId, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async deleteEvent(id, networkId, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.events.delete(id, networkId, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getEvent(id) {
|
|
||||||
try {
|
|
||||||
return global.db.events.getById(id)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getEvents(networkId) {
|
|
||||||
try {
|
|
||||||
return global.db.events.getByNetwork(networkId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async addJob(newJob, networkId, creatorId) {
|
|
||||||
try {
|
|
||||||
return await global.db.jobs.add(newJob, networkId, creatorId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async editJob(id, updatedJob, networkId, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.jobs.edit(id, updatedJob, networkId, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async deleteJob(id, networkId, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.jobs.delete(id, networkId, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getJob(id) {
|
|
||||||
try {
|
|
||||||
return await global.db.jobs.getById(id)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getJobs(networkId) {
|
|
||||||
try {
|
|
||||||
return global.db.jobs.getByNetwork(networkId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async addAnnouncement(text, networkId, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.announcements.add(text, networkId, userId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async editAnnouncement(newAnnouncement, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.announcements.edit(newAnnouncement, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async deleteAnnouncement(id, userId) {
|
|
||||||
try {
|
|
||||||
return await global.db.announcements.delete(id, userId);
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getAnnouncement(id) {
|
|
||||||
try {
|
|
||||||
return global.db.announcements.getById(id)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getAnnouncements(networkId) {
|
|
||||||
try {
|
|
||||||
return global.db.announcements.getByNetwork(networkId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getUserAnnouncements(userId) {
|
|
||||||
try {
|
|
||||||
return global.db.announcements.getByCreator(userId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async editBio(newBio, userId) {
|
|
||||||
try {
|
|
||||||
return global.db.members.editBio(newBio, userId)
|
|
||||||
} catch (e) {
|
|
||||||
return { status: e.status, error: e.message }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default handlers
|
|
||||||
10
src/_/code/bridge/server.js
Normal file
10
src/_/code/bridge/server.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { createBridge, IS_NODE } from "./bridge.js"
|
||||||
|
|
||||||
|
let handlers = {}
|
||||||
|
|
||||||
|
if (IS_NODE) {
|
||||||
|
const mod = await import("./serverFunctions.js")
|
||||||
|
handlers = mod.default
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createBridge(handlers)
|
||||||
@@ -1,10 +1,143 @@
|
|||||||
import { createBridge, IS_NODE } from "./bridge.js"
|
const handlers = {
|
||||||
|
async getStripeProfile(networkId) {
|
||||||
|
return global.payments.getProfile(networkId)
|
||||||
|
},
|
||||||
|
|
||||||
let handlers = {}
|
async addEvent(newEvent, networkId, creatorId) {
|
||||||
|
try {
|
||||||
|
return await global.db.events.add(newEvent, networkId, creatorId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
if (IS_NODE) {
|
async editEvent(id, updatedEvent, networkId, userId) {
|
||||||
const mod = await import("./handlers.js")
|
try {
|
||||||
handlers = mod.default
|
return await global.db.events.edit(id, updatedEvent, networkId, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteEvent(id, networkId, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.events.delete(id, networkId, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getEvent(id) {
|
||||||
|
try {
|
||||||
|
return global.db.events.getById(id)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getEvents(networkId) {
|
||||||
|
try {
|
||||||
|
return global.db.events.getByNetwork(networkId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async addJob(newJob, networkId, creatorId) {
|
||||||
|
try {
|
||||||
|
return await global.db.jobs.add(newJob, networkId, creatorId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async editJob(id, updatedJob, networkId, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.jobs.edit(id, updatedJob, networkId, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteJob(id, networkId, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.jobs.delete(id, networkId, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getJob(id) {
|
||||||
|
try {
|
||||||
|
return await global.db.jobs.getById(id)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getJobs(networkId) {
|
||||||
|
try {
|
||||||
|
return global.db.jobs.getByNetwork(networkId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async addAnnouncement(text, networkId, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.add(text, networkId, userId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async editAnnouncement(newAnnouncement, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.edit(newAnnouncement, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteAnnouncement(id, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.delete(id, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAnnouncement(id) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getById(id)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAnnouncements(networkId) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getByNetwork(networkId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getUserAnnouncements(userId) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getByCreator(userId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async editBio(newBio, userId) {
|
||||||
|
try {
|
||||||
|
return global.db.members.editBio(newBio, userId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createBridge(handlers)
|
export default handlers
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
--darkgrey: #5c4646;
|
--darkgrey: #5c4646;
|
||||||
|
|
||||||
--headertext: #433c36e2;
|
--headertext: #433c36e2;
|
||||||
--searchbackground: #dfc9ac;
|
--searchbackground: #ffeed8;
|
||||||
--loginButton: var(--main);
|
--loginButton: var(--main);
|
||||||
--loginBackground: #d96b6b;
|
--loginBackground: #d96b6b;
|
||||||
|
|
||||||
@@ -83,21 +83,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
outline: none;
|
||||||
|
caret-color: var(--text); /* hide real caret */
|
||||||
|
}
|
||||||
|
|
||||||
input::placeholder {
|
input::placeholder {
|
||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
|
color: #5C504D;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: var(--main);
|
background-color: var(--main);
|
||||||
padding-top: env(safe-area-inset-top);
|
padding-top: env(safe-area-inset-top);
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
padding-left: env(safe-area-inset-left);
|
padding-left: env(safe-area-inset-left);
|
||||||
padding-right: env(safe-area-inset-right);
|
padding-right: env(safe-area-inset-right);
|
||||||
}
|
}
|
||||||
90
src/apps/Announcements/Announcement.js
Normal file
90
src/apps/Announcements/Announcement.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import util from "../../util"
|
||||||
|
import server from "../../_/code/bridge/server.js"
|
||||||
|
|
||||||
|
css(`
|
||||||
|
announcement- p {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: var(--darktext);
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
class Announcement extends Shadow {
|
||||||
|
constructor(announcement) {
|
||||||
|
super()
|
||||||
|
this.announcement = announcement
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
VStack(() => {
|
||||||
|
HStack(() => {
|
||||||
|
h3(this.announcement.message)
|
||||||
|
.color("var(--text)")
|
||||||
|
.fontSize(1.3, em)
|
||||||
|
.fontWeight("normal")
|
||||||
|
.margin(0, em)
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
// if (this.announcement.creator_id === global.profile.id) {
|
||||||
|
// img(util.cssVariable("trash-src"), "1.5em")
|
||||||
|
// .marginRight(0.5, em)
|
||||||
|
// .onTap(() => {
|
||||||
|
// this.deleteAnnouncement(this.announcement)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
.justifyContent("space-between")
|
||||||
|
.verticalAlign("center")
|
||||||
|
|
||||||
|
p(this.announcement.author ?? "Unknown author")
|
||||||
|
.marginTop(0.75, em)
|
||||||
|
p(this.convertDate(this.announcement.created) ?? "No date included")
|
||||||
|
.marginTop(0.25, em)
|
||||||
|
})
|
||||||
|
.paddingVertical(1.5, em)
|
||||||
|
.paddingHorizontal(3.5, em)
|
||||||
|
.marginHorizontal(1, em)
|
||||||
|
.borderRadius(10, px)
|
||||||
|
.background("var(--darkaccent)")
|
||||||
|
.border("1px solid var(--accent)")
|
||||||
|
.boxSizing("border-box")
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAnnouncement(announcement) {
|
||||||
|
const result = await server.deleteAnnouncement(announcement.id, announcement.network_id, global.profile.id)
|
||||||
|
if (result.data === null) {
|
||||||
|
console.log("Failed to delete announcement")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 hours24 = parsed.getUTCHours();
|
||||||
|
const minutes = parsed.getUTCMinutes();
|
||||||
|
|
||||||
|
const hours12 = hours24 % 12 || 12;
|
||||||
|
const ampm = hours24 >= 12 ? "PM" : "AM";
|
||||||
|
const paddedMinutes = String(minutes).padStart(2, "0");
|
||||||
|
|
||||||
|
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} at ${hours12}:${paddedMinutes} ${ampm}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register(Announcement)
|
||||||
@@ -1,125 +1,176 @@
|
|||||||
import './Panel.js'
|
import './Announcement.js'
|
||||||
import server from '../../_/code/bridge/serverFunctions.js'
|
import server from '../../_/code/bridge/server.js'
|
||||||
|
import '../../components/SearchBar.js'
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
announcements- {
|
announcements- {
|
||||||
|
font-family: 'Arial';
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
announcements- h1 {
|
||||||
font-family: 'Bona';
|
font-family: 'Bona';
|
||||||
}
|
}
|
||||||
|
|
||||||
announcements- input::placeholder {
|
announcements- .VStack::-webkit-scrollbar {
|
||||||
font-family: 'Bona Nova';
|
display: none;
|
||||||
font-size: 0.9em;
|
width: 0px;
|
||||||
color: var(--accent);
|
height: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::placeholder {
|
announcements- .VStack::-webkit-scrollbar-thumb {
|
||||||
font-family: Arial;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
announcements- .VStack::-webkit-scrollbar-track {
|
||||||
appearance: none; /* remove default style */
|
background: transparent;
|
||||||
-webkit-appearance: none;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
border: 1px solid var(--accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="checkbox"]:checked {
|
|
||||||
background-color: var(--red);
|
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
class Announcements extends Shadow {
|
class Announcements extends Shadow {
|
||||||
announcements;
|
static searchableKeys = ['message', 'author'];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.announcements = global.currentNetwork.data.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
this.announcements = global.currentNetwork.data.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
console.log(this.announcements)
|
this.searchedAnnouncements = [];
|
||||||
}
|
this.searchText = "";
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
ZStack(() => {
|
ZStack(() => {
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
|
SearchBar(this.searchText, "90vw")
|
||||||
|
|
||||||
Panel(this.announcements)
|
VStack(() => {
|
||||||
|
if (!this.announcements || this.announcements == []) {
|
||||||
input("Message", "70%")
|
LoadingCircle()
|
||||||
.paddingVertical(0.75, em)
|
} else if (this.searchText) {
|
||||||
.boxSizing("border-box")
|
if (this.searchedAnnouncements.length > 0) {
|
||||||
.paddingHorizontal(2, em)
|
for (let i = 0; i < this.searchedAnnouncements.length; i++) {
|
||||||
.color("var(--text)")
|
AnnouncementCard(this.searchedAnnouncements[i])
|
||||||
.background("var(--searchbackground)")
|
|
||||||
.marginBottom(1, em)
|
|
||||||
.border("0.5px solid var(--accent)")
|
|
||||||
.outline("none")
|
|
||||||
.borderRadius(100, px)
|
|
||||||
.fontFamily("Arial")
|
|
||||||
.fontSize(1, em)
|
|
||||||
.onKeyDown(async function(e) {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
const result = await server.addAnnouncement(this.value, global.currentNetwork.id, global.profile.id)
|
|
||||||
if (result.data.status === 200) {
|
|
||||||
window.dispatchEvent(new CustomEvent('new-announcement', {
|
|
||||||
detail: { announcement: result.data.announcement }
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
// error
|
|
||||||
}
|
}
|
||||||
this.value = ""
|
} else {
|
||||||
|
h2("Could not find any announcements with your search criteria.")
|
||||||
|
.color("var(--divider)")
|
||||||
|
.fontWeight("bold")
|
||||||
|
.marginTop(7.5, em)
|
||||||
|
.marginBottom(0.5, em)
|
||||||
|
.textAlign("center")
|
||||||
}
|
}
|
||||||
|
} else if (this.announcements.length > 0) {
|
||||||
|
for (let i = 0; i < this.announcements.length; i++) {
|
||||||
|
AnnouncementCard(this.announcements[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h2("No Announcements")
|
||||||
|
.color("var(--divider)")
|
||||||
|
.fontWeight("bold")
|
||||||
|
.marginTop(7.5, em)
|
||||||
|
.marginBottom(0.5, em)
|
||||||
|
.textAlign("center")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.overflowY("scroll")
|
||||||
|
.gap(0.75, em)
|
||||||
|
|
||||||
|
if(global.currentNetwork.permissions.includes("announcements.add")) {
|
||||||
|
HStack(() => {
|
||||||
|
input("Image Upload", "0px", "0px")
|
||||||
|
.attr({ name: "image-upload", type: "file" })
|
||||||
|
.display("none")
|
||||||
|
.visibility("hidden")
|
||||||
|
.onChange((e) => {
|
||||||
|
this.handleUpload(e.target.files[0]);
|
||||||
|
})
|
||||||
|
|
||||||
|
div("+")
|
||||||
|
.width(3, rem)
|
||||||
|
.height(3, rem)
|
||||||
|
.borderRadius(50, pct)
|
||||||
|
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
||||||
|
.fontSize(2, em)
|
||||||
|
.transform("rotate(180deg)")
|
||||||
|
.zIndex(1001)
|
||||||
|
.display("flex")
|
||||||
|
.alignItems("center")
|
||||||
|
.justifyContent("center")
|
||||||
|
.transition("scale .2s")
|
||||||
|
.state("touched", function (touched) {
|
||||||
|
if(touched) {
|
||||||
|
this.scale("1.5")
|
||||||
|
this.color("var(--darkaccent)")
|
||||||
|
this.backgroundColor("var(--divider)")
|
||||||
|
} else {
|
||||||
|
this.scale("")
|
||||||
|
this.color("var(--divider)")
|
||||||
|
this.backgroundColor("var(--searchbackground)")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onTouch(function (start) {
|
||||||
|
if(start) {
|
||||||
|
this.attr({touched: "true"})
|
||||||
|
} else {
|
||||||
|
this.attr({touched: ""})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onClick((done) => {
|
||||||
|
if(done) {
|
||||||
|
const inputSelector = this.$('[name="image-upload"]');
|
||||||
|
inputSelector.click()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
input("Add an Announcement")
|
||||||
|
.flex("1 1 auto")
|
||||||
|
.minWidth(0)
|
||||||
|
.color("var(--text)")
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.paddingVertical(0, rem)
|
||||||
|
.fontSize(1, rem)
|
||||||
|
.paddingHorizontal(1, rem)
|
||||||
|
.borderRadius(100, px)
|
||||||
|
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
||||||
|
.onTouch(function (start) {
|
||||||
|
if (start) {
|
||||||
|
this.style.backgroundColor = "var(--accent)"
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
$("appmenu-").display("none")
|
||||||
|
}, 20)
|
||||||
|
console.log($("appmenu-"))
|
||||||
|
this.style.backgroundColor = "var(--searchbackground)"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addEventListener("blur", () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
$("appmenu-").display("grid")
|
||||||
|
}, 20)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
.width(100, pct)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.position("absolute")
|
||||||
|
.paddingHorizontal(1, rem)
|
||||||
|
.bottom(1, vh)
|
||||||
|
.gap(0.5, rem)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.gap(1, em)
|
|
||||||
.boxSizing("border-box")
|
.boxSizing("border-box")
|
||||||
.width(100, pct)
|
|
||||||
.height(100, pct)
|
.height(100, pct)
|
||||||
.horizontalAlign("center")
|
.width(100, pct)
|
||||||
.verticalAlign("end")
|
.onEvent("announcementsearch", this.onAnnouncementSearch)
|
||||||
.minHeight(0)
|
.onEvent("new-announcement", this.onNewAnnouncement)
|
||||||
|
.onEvent("deleted-announcement", this.onDeletedAnnouncement)
|
||||||
|
.onEvent("edited-announcement", this.onEditedAnnouncement)
|
||||||
})
|
})
|
||||||
.backgroundColor("var(--main)")
|
|
||||||
.boxSizing("border-box")
|
|
||||||
.paddingVertical(1, em)
|
|
||||||
.width(100, pct)
|
|
||||||
.height(100, pct)
|
|
||||||
.flex("1 1 auto")
|
|
||||||
.onEvent("new-announcement", this.onNewAnnouncement)
|
|
||||||
.onEvent("deleted-announcement", this.onDeletedAnnouncement)
|
|
||||||
.onEvent("edited-announcement", this.onEditedAnnouncement)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
addPhoto() {
|
||||||
this.getAnnouncements(global.currentNetwork.id)
|
console.log("hey")
|
||||||
}
|
|
||||||
|
|
||||||
checkForUpdates(currentAnnouncements, fetchedAnnouncements) {
|
|
||||||
if (currentAnnouncements.length !== fetchedAnnouncements.length) return true;
|
|
||||||
|
|
||||||
const currentMap = new Map(currentAnnouncements.map(ann => [ann.id, ann]));
|
|
||||||
|
|
||||||
for (const fetchedAnn of fetchedAnnouncements) {
|
|
||||||
const currentAnn = currentMap.get(fetchedAnn.id);
|
|
||||||
|
|
||||||
// new event added
|
|
||||||
if (!currentAnn) return true;
|
|
||||||
|
|
||||||
// existing event changed
|
|
||||||
if (currentAnn.updated_at !== fetchedAnn.updated_at) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAnnouncements(networkId) {
|
|
||||||
const fetchedAnnouncements = await server.getAnnouncements(networkId)
|
|
||||||
if (this.checkForUpdates(this.announcements, fetchedAnnouncements.data)) {
|
|
||||||
console.log("found updates")
|
|
||||||
this.announcements = fetchedAnnouncements.data.sort((a, b) => new Date(b.created) - new Date(a.created));
|
|
||||||
global.currentNetwork.data.announcements = this.announcements
|
|
||||||
this.rerender()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewAnnouncement = (e) => {
|
onNewAnnouncement = (e) => {
|
||||||
@@ -138,13 +189,54 @@ class Announcements extends Shadow {
|
|||||||
|
|
||||||
onEditedAnnouncement = (e) => {
|
onEditedAnnouncement = (e) => {
|
||||||
let editedAnnouncement = e.detail
|
let editedAnnouncement = e.detail
|
||||||
const i = this.announcements.findIndex(ann => ann.id === editedPost.id)
|
const i = this.announcements.findIndex(ann => ann.id === editedAnnouncement.id)
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
this.announcements.splice(i, 1)
|
this.announcements.splice(i, 1)
|
||||||
this.announcements.unshift(editedAnnouncement)
|
this.announcements.unshift(editedAnnouncement)
|
||||||
}
|
}
|
||||||
this.rerender()
|
this.rerender()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAnnouncementSearch = (e) => {
|
||||||
|
let searchText = e.detail.searchText.toLowerCase().trim();
|
||||||
|
if (!searchText) {
|
||||||
|
this.searchedAnnouncements = [];
|
||||||
|
} else {
|
||||||
|
this.searchedAnnouncements = this.announcements.filter(announcement =>
|
||||||
|
Announcements.searchableKeys.some(key =>
|
||||||
|
String(announcement[key]).toLowerCase().includes(searchText)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.searchText = searchText
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAnnouncements(networkId) {
|
||||||
|
const fetchedAnnouncements = await server.getAnnouncements(networkId)
|
||||||
|
if (this.checkForUpdates(this.announcements, fetchedAnnouncements.data)) {
|
||||||
|
this.announcements = fetchedAnnouncements.data.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
global.currentNetwork.data.announcements = this.announcements
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.getAnnouncements(global.currentNetwork.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdates(currentAnnouncements, fetchedAnnouncements) {
|
||||||
|
if (currentAnnouncements.length !== fetchedAnnouncements.length) return true;
|
||||||
|
|
||||||
|
const currentMap = new Map(currentAnnouncements.map(ann => [ann.id, ann]));
|
||||||
|
|
||||||
|
for (const fetchedAnn of fetchedAnnouncements) {
|
||||||
|
const currentAnn = currentMap.get(fetchedAnn.id);
|
||||||
|
if (!currentAnn) return true;
|
||||||
|
if (currentAnn.updated_at !== fetchedAnn.updated_at) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register(Announcements)
|
register(Announcements)
|
||||||
150
src/apps/Announcements/Old.js
Normal file
150
src/apps/Announcements/Old.js
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import './Panel.js'
|
||||||
|
import server from '../../_/code/bridge/serverFunctions.js'
|
||||||
|
|
||||||
|
css(`
|
||||||
|
announcements- {
|
||||||
|
font-family: 'Bona';
|
||||||
|
}
|
||||||
|
|
||||||
|
announcements- input::placeholder {
|
||||||
|
font-family: 'Bona Nova';
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
appearance: none; /* remove default style */
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked {
|
||||||
|
background-color: var(--red);
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
class Announcements extends Shadow {
|
||||||
|
announcements;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.announcements = global.currentNetwork.data.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
console.log(this.announcements)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
ZStack(() => {
|
||||||
|
VStack(() => {
|
||||||
|
|
||||||
|
Panel(this.announcements)
|
||||||
|
|
||||||
|
input("Message", "70%")
|
||||||
|
.paddingVertical(0.75, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.paddingHorizontal(2, em)
|
||||||
|
.color("var(--text)")
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.marginBottom(1, em)
|
||||||
|
.border("0.5px solid var(--accent)")
|
||||||
|
.outline("none")
|
||||||
|
.borderRadius(100, px)
|
||||||
|
.fontFamily("Arial")
|
||||||
|
.fontSize(1, em)
|
||||||
|
.onKeyDown(async function(e) {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
const result = await server.addAnnouncement(this.value, global.currentNetwork.id, global.profile.id)
|
||||||
|
if (result.data.status === 200) {
|
||||||
|
window.dispatchEvent(new CustomEvent('new-announcement', {
|
||||||
|
detail: { announcement: result.data.announcement }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
this.value = ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.gap(1, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.width(100, pct)
|
||||||
|
.height(100, pct)
|
||||||
|
.horizontalAlign("center")
|
||||||
|
.verticalAlign("end")
|
||||||
|
.minHeight(0)
|
||||||
|
})
|
||||||
|
.backgroundColor("var(--main)")
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.paddingVertical(1, em)
|
||||||
|
.width(100, pct)
|
||||||
|
.height(100, pct)
|
||||||
|
.flex("1 1 auto")
|
||||||
|
.onEvent("new-announcement", this.onNewAnnouncement)
|
||||||
|
.onEvent("deleted-announcement", this.onDeletedAnnouncement)
|
||||||
|
.onEvent("edited-announcement", this.onEditedAnnouncement)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.getAnnouncements(global.currentNetwork.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdates(currentAnnouncements, fetchedAnnouncements) {
|
||||||
|
if (currentAnnouncements.length !== fetchedAnnouncements.length) return true;
|
||||||
|
|
||||||
|
const currentMap = new Map(currentAnnouncements.map(ann => [ann.id, ann]));
|
||||||
|
|
||||||
|
for (const fetchedAnn of fetchedAnnouncements) {
|
||||||
|
const currentAnn = currentMap.get(fetchedAnn.id);
|
||||||
|
|
||||||
|
// new event added
|
||||||
|
if (!currentAnn) return true;
|
||||||
|
|
||||||
|
// existing event changed
|
||||||
|
if (currentAnn.updated_at !== fetchedAnn.updated_at) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAnnouncements(networkId) {
|
||||||
|
const fetchedAnnouncements = await server.getAnnouncements(networkId)
|
||||||
|
if (this.checkForUpdates(this.announcements, fetchedAnnouncements.data)) {
|
||||||
|
console.log("found updates")
|
||||||
|
this.announcements = fetchedAnnouncements.data.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
global.currentNetwork.data.announcements = this.announcements
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNewAnnouncement = (e) => {
|
||||||
|
let newAnnouncement = e.detail.announcement;
|
||||||
|
this.announcements.push(newAnnouncement)
|
||||||
|
this.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeletedAnnouncement = (e) => {
|
||||||
|
let deletedId = e.detail.id
|
||||||
|
const i = this.announcements.findIndex(ann => ann.id === deletedId)
|
||||||
|
if (i !== -1) this.announcements.splice(i, 1);
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditedAnnouncement = (e) => {
|
||||||
|
let editedAnnouncement = e.detail
|
||||||
|
const i = this.announcements.findIndex(ann => ann.id === editedPost.id)
|
||||||
|
if (i !== -1) {
|
||||||
|
this.announcements.splice(i, 1)
|
||||||
|
this.announcements.unshift(editedAnnouncement)
|
||||||
|
}
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register(Announcements)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import "../../components/LoadingCircle.js"
|
import "../../components/LoadingCircle.js"
|
||||||
import server from "../../_/code/bridge/serverFunctions.js"
|
import server from "../../_/code/bridge/server.js"
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
panel- {
|
panel- {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import util from "../../util"
|
import util from "../../util"
|
||||||
import server from "../../_/code/bridge/serverFunctions.js"
|
import server from "../../_/code/bridge/server.js"
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
eventcard- p {
|
eventcard- p {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import server from "../../_/code/bridge/serverFunctions"
|
import server from "../../_/code/bridge/server"
|
||||||
|
|
||||||
class EventForm extends Shadow {
|
class EventForm extends Shadow {
|
||||||
inputStyles(el) {
|
inputStyles(el) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import "../../components/TopBar.js"
|
|||||||
import "../../components/LoadingCircle.js"
|
import "../../components/LoadingCircle.js"
|
||||||
import "./EventCard.js"
|
import "./EventCard.js"
|
||||||
import "./EventForm.js"
|
import "./EventForm.js"
|
||||||
import server from "../../_/code/bridge/serverFunctions.js"
|
import server from "../../_/code/bridge/server.js"
|
||||||
import "../../components/SearchBar.js"
|
import "../../components/SearchBar.js"
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
@@ -47,7 +47,10 @@ class Events extends Shadow {
|
|||||||
EventForm()
|
EventForm()
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
SearchBar(this.searchText)
|
HStack(() => {
|
||||||
|
SearchBar(this.searchText, "75vw")
|
||||||
|
AddButton()
|
||||||
|
})
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
if (!this.events || this.events == []) {
|
if (!this.events || this.events == []) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import util from "../../util.js"
|
import util from "../../util.js"
|
||||||
import server from "../../_/code/bridge/serverFunctions.js"
|
import server from "../../_/code/bridge/server.js"
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
jobcard- p {
|
jobcard- p {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import server from "../../_/code/bridge/serverFunctions"
|
import server from "../../_/code/bridge/server"
|
||||||
|
|
||||||
class JobForm extends Shadow {
|
class JobForm extends Shadow {
|
||||||
inputStyles(el) {
|
inputStyles(el) {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import "./JobsGrid.js"
|
|||||||
import "./JobCard.js"
|
import "./JobCard.js"
|
||||||
import "./JobForm.js"
|
import "./JobForm.js"
|
||||||
import "../../components/SearchBar.js"
|
import "../../components/SearchBar.js"
|
||||||
import server from "../../_/code/bridge/serverFunctions.js"
|
import "../../components/AddButton.js"
|
||||||
|
import server from "../../_/code/bridge/server.js"
|
||||||
|
|
||||||
css(`
|
css(`
|
||||||
jobs- {
|
jobs- {
|
||||||
@@ -47,7 +48,10 @@ class Jobs extends Shadow {
|
|||||||
JobForm()
|
JobForm()
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
SearchBar(this.searchText)
|
HStack(() => {
|
||||||
|
SearchBar(this.searchText, "75vw")
|
||||||
|
AddButton()
|
||||||
|
})
|
||||||
|
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
if (!this.jobs || this.jobs == []) {
|
if (!this.jobs || this.jobs == []) {
|
||||||
|
|||||||
33
src/components/AddButton.js
Normal file
33
src/components/AddButton.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
class AddButton extends Shadow {
|
||||||
|
render() {
|
||||||
|
p("+")
|
||||||
|
.fontWeight("bolder")
|
||||||
|
.paddingVertical(0.75, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.paddingHorizontal(1, em)
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.color("var(--accent)")
|
||||||
|
.marginBottom(1, em)
|
||||||
|
.border("1px solid var(--accent)")
|
||||||
|
.borderRadius(15, px)
|
||||||
|
.onTap(() => {
|
||||||
|
this.handleAdd()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAdd() {
|
||||||
|
const app = global.currentApp()
|
||||||
|
switch (app) {
|
||||||
|
case "Jobs":
|
||||||
|
$("jobform-").toggle()
|
||||||
|
break;
|
||||||
|
case "Events":
|
||||||
|
$("eventform-").toggle()
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register(AddButton)
|
||||||
@@ -5,97 +5,68 @@ css(`
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
class SearchBar extends Shadow {
|
class SearchBar extends Shadow {
|
||||||
constructor(searchText) {
|
searchText
|
||||||
super()
|
width
|
||||||
this.searchText = searchText
|
|
||||||
}
|
|
||||||
|
|
||||||
|
constructor(searchText, width) {
|
||||||
|
super()
|
||||||
|
this.searchText = searchText
|
||||||
|
this.width = width
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
form(() => {
|
form(() => {
|
||||||
HStack(() => {
|
input("Search", this.width)
|
||||||
input("Search", "80%")
|
.attr({ name: "searchText", type: "text" })
|
||||||
.attr({ name: "searchText", type: "text" })
|
.attr({ value: this.searchText ? this.searchText : "" })
|
||||||
.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)
|
.background("var(--searchbackground)")
|
||||||
.background("var(--searchbackground)")
|
.color("gray")
|
||||||
.color("gray")
|
.marginBottom(1, em)
|
||||||
.marginBottom(1, em)
|
.marginLeft(1, em)
|
||||||
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
.marginRight(0.5, em)
|
||||||
.borderRadius(100, px)
|
.border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
|
||||||
.fontFamily("Arial")
|
.borderRadius(100, px)
|
||||||
.fontSize(1, em)
|
.fontFamily("Arial")
|
||||||
.outline("none")
|
.fontSize(1, em)
|
||||||
.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();
|
.onSubmit(async (e) => {
|
||||||
// console.log("helloooo submitted")
|
e.preventDefault();
|
||||||
// }) // can be used for live updating
|
const data = new FormData(e.target);
|
||||||
|
this.dispatchSearchEvent(data.get("searchText"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
p("+")
|
dispatchSearchEvent(searchText) {
|
||||||
.fontWeight("bolder")
|
const app = global.currentApp();
|
||||||
.paddingVertical(0.75, em)
|
switch (app) {
|
||||||
.boxSizing("border-box")
|
case "Jobs":
|
||||||
.paddingHorizontal(1, em)
|
window.dispatchEvent(new CustomEvent('jobsearch', {
|
||||||
.background("var(--searchbackground)")
|
detail: { searchText: searchText }
|
||||||
.color("var(--accent)")
|
}));
|
||||||
.marginBottom(1, em)
|
break;
|
||||||
.border("1px solid var(--accent)")
|
case "Events":
|
||||||
.borderRadius(15, px)
|
window.dispatchEvent(new CustomEvent('eventsearch', {
|
||||||
.onTap(() => {
|
detail: { searchText: searchText }
|
||||||
this.handleAdd()
|
}));
|
||||||
})
|
break;
|
||||||
})
|
case "Announcements":
|
||||||
.width(100, pct)
|
window.dispatchEvent(new CustomEvent('announcementsearch', {
|
||||||
.horizontalAlign("center")
|
detail: { searchText: searchText }
|
||||||
.verticalAlign("center")
|
}));
|
||||||
.gap(0.5, em)
|
break;
|
||||||
})
|
}
|
||||||
.onSubmit(async (e) => {
|
}
|
||||||
e.preventDefault();
|
|
||||||
const data = new FormData(e.target);
|
|
||||||
this.dispatchSearchEvent(data.get("searchText"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAdd() {
|
|
||||||
const app = global.currentApp()
|
|
||||||
switch (app) {
|
|
||||||
case "Jobs":
|
|
||||||
$("jobform-").toggle()
|
|
||||||
break;
|
|
||||||
case "Events":
|
|
||||||
$("eventform-").toggle()
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register(SearchBar)
|
register(SearchBar)
|
||||||
31
src/index.js
31
src/index.js
@@ -1,3 +1,6 @@
|
|||||||
|
import { PushNotifications } from '@capacitor/push-notifications';
|
||||||
|
|
||||||
|
import server from './_/code/bridge/server.js'
|
||||||
import Socket from "/_/code/ws/Socket.js"
|
import Socket from "/_/code/ws/Socket.js"
|
||||||
import "./Home/Home.js"
|
import "./Home/Home.js"
|
||||||
import "./Home/AuthPage/AuthPage.js"
|
import "./Home/AuthPage/AuthPage.js"
|
||||||
@@ -12,7 +15,7 @@ let Global = class {
|
|||||||
|
|
||||||
currentApp() {
|
currentApp() {
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const segments = pathname.split('/').filter(Boolean);
|
const segments = pathname.split('/').filter(Boolean)
|
||||||
const secondSegment = segments[1] || ""
|
const secondSegment = segments[1] || ""
|
||||||
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
||||||
return capitalized
|
return capitalized
|
||||||
@@ -154,7 +157,33 @@ let Global = class {
|
|||||||
location.reload()
|
location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setupPushNotifications() {
|
||||||
|
const permission = await PushNotifications.requestPermissions();
|
||||||
|
|
||||||
|
if (permission.receive === 'granted') {
|
||||||
|
await PushNotifications.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
PushNotifications.addListener('registration', async (token) => {
|
||||||
|
console.log('Device token:', token.value)
|
||||||
|
const stored = localStorage.getItem('deviceToken')
|
||||||
|
if (stored === token.value) return;
|
||||||
|
|
||||||
|
await server.updatePushToken(token.value)
|
||||||
|
localStorage.setItem('deviceToken', token.value)
|
||||||
|
});
|
||||||
|
|
||||||
|
PushNotifications.addListener('registrationError', (error) => {
|
||||||
|
console.error('Registration error:', error)
|
||||||
|
});
|
||||||
|
|
||||||
|
PushNotifications.addListener('pushNotificationReceived', (notification) => {
|
||||||
|
console.log('Notification received:', notification)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.setupPushNotifications()
|
||||||
window.addEventListener("navigate", this.onNavigate)
|
window.addEventListener("navigate", this.onNavigate)
|
||||||
|
|
||||||
this.getProfile().then(async (status) => {
|
this.getProfile().then(async (status) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user