switching networks works, established server functions
This commit is contained in:
@@ -20,6 +20,15 @@ class Dashboard extends Shadow {
|
||||
|
||||
render() {
|
||||
VStack(() => {
|
||||
|
||||
if(window.location.pathname.startsWith("/my")) {
|
||||
h1(global.profile.name);
|
||||
return
|
||||
}
|
||||
else if(!window.location.pathname.includes("comalyr")) {
|
||||
return
|
||||
}
|
||||
|
||||
h1("Website Inquiries");
|
||||
|
||||
p("Contact Us")
|
||||
@@ -41,7 +50,7 @@ class Dashboard extends Shadow {
|
||||
.maxWidth(95, pct)
|
||||
.gap(8);
|
||||
|
||||
window.currentNetwork.data.contact.forEach((entry) => {
|
||||
global.currentNetwork.data.contact.forEach((entry) => {
|
||||
HStack(() => {
|
||||
this.cell("time", entry.time);
|
||||
this.cell("fname", entry.fname);
|
||||
@@ -74,7 +83,7 @@ class Dashboard extends Shadow {
|
||||
.maxWidth(95, pct)
|
||||
.gap(8);
|
||||
|
||||
window.currentNetwork.data.join.forEach((entry) => {
|
||||
global.currentNetwork.data.join.forEach((entry) => {
|
||||
HStack(() => {
|
||||
this.cell("time", entry.time);
|
||||
this.cell("fname", entry.fname);
|
||||
|
||||
@@ -79,7 +79,7 @@ class Forum extends Shadow {
|
||||
.fontSize(1, em)
|
||||
.onKeyDown(function (e) {
|
||||
if (e.key === "Enter") {
|
||||
window.Socket.send({app: "FORUM", operation: "SEND", msg: {forum: "HY", text: this.value }})
|
||||
global.Socket.send({app: "FORUM", operation: "SEND", msg: {forum: "HY", text: this.value }})
|
||||
this.value = ""
|
||||
}
|
||||
})
|
||||
|
||||
@@ -65,7 +65,7 @@ class Messages extends Shadow {
|
||||
.fontSize(1, em)
|
||||
.onKeyDown((e) => {
|
||||
if (e.key === "Enter") {
|
||||
window.Socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
|
||||
global.Socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
|
||||
e.target.value = ""
|
||||
}
|
||||
})
|
||||
@@ -104,7 +104,7 @@ class Messages extends Shadow {
|
||||
.color("var(--accent)")
|
||||
.onKeyDown(function (e) {
|
||||
if (e.key === "Enter") {
|
||||
window.Socket.send({app: "MESSAGES", operation: "ADDCONVERSATION", msg: {email: this.value }})
|
||||
global.Socket.send({app: "MESSAGES", operation: "ADDCONVERSATION", msg: {email: this.value }})
|
||||
this.value = ""
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ class MessagesPanel extends Shadow {
|
||||
if(this.messages) {
|
||||
for(let i=0; i<this.messages.length; i++) {
|
||||
let message = this.messages[i]
|
||||
let fromMe = window.profile.email === message.from.email
|
||||
let fromMe = global.profile.email === message.from.email
|
||||
VStack(() => {
|
||||
HStack(() => {
|
||||
p(message.from.firstName + " " + message.from.lastName)
|
||||
|
||||
@@ -57,7 +57,7 @@ class MessagesSidebar extends Shadow {
|
||||
let membersString = ""
|
||||
for(let i=0; i<members.length; i++) {
|
||||
let member = members[i]
|
||||
if(member.email === window.profile.email) {
|
||||
if(member.email === global.profile.email) {
|
||||
continue;
|
||||
}
|
||||
if(members.length > 2) {
|
||||
|
||||
@@ -5,8 +5,8 @@ class People extends Shadow {
|
||||
.fontWeight("bold")
|
||||
.marginBottom(2, em)
|
||||
|
||||
for(let i = 0; i < window.currentNetwork.data.members.length; i++) {
|
||||
let member = window.currentNetwork.data.members[i]
|
||||
for(let i = 0; i < global.currentNetwork.data.members.length; i++) {
|
||||
let member = global.currentNetwork.data.members[i]
|
||||
HStack(() => {
|
||||
p(member.firstName + " " + member.lastName)
|
||||
.width(10, pct)
|
||||
|
||||
@@ -15,9 +15,9 @@ class AppMenu extends Shadow {
|
||||
}
|
||||
|
||||
HStack(() => {
|
||||
let currentNetwork = window.currentNetwork
|
||||
let currentNetwork = global.currentNetwork
|
||||
if(!currentNetwork) return
|
||||
let currentApp = window.currentApp
|
||||
let currentApp = global.currentApp
|
||||
|
||||
for(let i = 0; i < currentNetwork.apps.length; i++) {
|
||||
let app = currentNetwork.apps[i]
|
||||
@@ -27,7 +27,7 @@ class AppMenu extends Shadow {
|
||||
.paddingBottom(currentApp === app ? 4 : 5, px)
|
||||
.borderBottom(currentApp === app ? "1px solid var(--accent)" : "")
|
||||
.onClick((done) => {
|
||||
if(done) window.openApp(app)
|
||||
if(done) global.openApp(app)
|
||||
})
|
||||
.onHover(function (hovering) {
|
||||
if(hovering) {
|
||||
@@ -49,6 +49,10 @@ class AppMenu extends Shadow {
|
||||
// console.log("app hello?") // BUG: Quill is not acknowledging this event unless there is something else in the function body
|
||||
this.rerender()
|
||||
})
|
||||
.onEvent("networkchange", () => {
|
||||
// console.log(global.currentApp)
|
||||
this.rerender()
|
||||
})
|
||||
.position("fixed")
|
||||
.x(0).yBottom(0)
|
||||
.width(100, vw)
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppWindow extends Shadow {
|
||||
|
||||
render() {
|
||||
ZStack(() => {
|
||||
switch(window.currentApp) {
|
||||
switch(global.currentApp) {
|
||||
case "Dashboard":
|
||||
Dashboard()
|
||||
break;
|
||||
@@ -33,17 +33,20 @@ class AppWindow extends Shadow {
|
||||
})
|
||||
.overflow("scroll")
|
||||
.position("absolute")
|
||||
.onEvent("resize", () => {
|
||||
this.rerender()
|
||||
})
|
||||
.width(window.innerWidth - this.calculateWidth(), px)
|
||||
.height(window.innerHeight - this.calculateHeight(), px)
|
||||
.background("var(--app)")
|
||||
.x(this.calculateWidth(), px)
|
||||
.yBottom(this.calculateHeight(), px)
|
||||
.onEvent("resize", () => {
|
||||
this.rerender()
|
||||
})
|
||||
.onEvent("appchange", () => {
|
||||
this.rerender()
|
||||
})
|
||||
.onEvent("networkchange", () => {
|
||||
this.rerender()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ class ProfileMenu extends Shadow {
|
||||
p("Email: ")
|
||||
.fontWeight("bold")
|
||||
|
||||
p(window.profile?.email)
|
||||
p(global.profile?.email)
|
||||
})
|
||||
.gap(1, em)
|
||||
|
||||
@@ -16,7 +16,7 @@ class ProfileMenu extends Shadow {
|
||||
p("Name: ")
|
||||
.fontWeight("bold")
|
||||
|
||||
p(window.profile?.name)
|
||||
p(global.profile?.name)
|
||||
})
|
||||
.gap(1, em)
|
||||
|
||||
@@ -37,8 +37,8 @@ class ProfileMenu extends Shadow {
|
||||
.center()
|
||||
.display("none")
|
||||
.onAppear(async () => {
|
||||
if(!window.profile) {
|
||||
window.profile = await this.fetchProfile()
|
||||
if(!global.profile) {
|
||||
global.profile = await this.fetchProfile()
|
||||
this.rerender()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
class Sidebar extends Shadow {
|
||||
currentNetwork = null
|
||||
|
||||
toggleSelectedStyles(el) {
|
||||
let currentlySelected = $("img[selected]")
|
||||
if(currentlySelected) {
|
||||
currentlySelected.removeAttribute("selected")
|
||||
currentlySelected.style.borderLeft = ""
|
||||
currentlySelected.style.paddingLeft = "10px"
|
||||
}
|
||||
|
||||
el.setAttribute("selected", "")
|
||||
el.style.borderLeft = "1px solid var(--accent)"
|
||||
el.style.paddingLeft = "9px"
|
||||
}
|
||||
|
||||
render() {
|
||||
VStack(() => {
|
||||
let selected = window.location.pathname.startsWith("/my")
|
||||
|
||||
img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.5em", "2.5em")
|
||||
.marginTop(6, vh)
|
||||
.marginBottom(2, vh)
|
||||
.attr({selected: selected ? "" : null})
|
||||
.paddingRight(0.5, em)
|
||||
.paddingLeft(selected ? 9 : 10, px)
|
||||
.borderLeft(selected ? "1px solid var(--accent)" : "0")
|
||||
.onClick((done, e) => {
|
||||
if(done) {
|
||||
this.toggleSelectedStyles(e.target)
|
||||
window.navigateTo("/my")
|
||||
}
|
||||
})
|
||||
|
||||
let networks = window.profile.networks
|
||||
let networks = global.profile.networks
|
||||
for(let i=0; i<networks.length; i++) {
|
||||
let selected = window.location.pathname.startsWith("/" + networks[i].abbreviation)
|
||||
|
||||
img(`/db/images/${networks[i].logo}`, "2.25em", "2.25em")
|
||||
.marginTop(3, vh)
|
||||
.attr({selected: selected ? "" : null})
|
||||
.paddingRight(0.5, em)
|
||||
.paddingLeft(selected ? 9 : 10, px)
|
||||
.borderLeft(selected ? "1px solid var(--accent)" : "0")
|
||||
@@ -23,11 +48,10 @@ class Sidebar extends Shadow {
|
||||
this.style.opacity = ""
|
||||
}
|
||||
})
|
||||
.onClick(function (finished) {
|
||||
if(finished) {
|
||||
this.setAttribute("selected", "")
|
||||
this.style.borderLeft = "1px solid var(--accent)"
|
||||
this.style.paddingLeft = "9px"
|
||||
.onClick((done, e) => {
|
||||
if(done) {
|
||||
this.toggleSelectedStyles(e.target)
|
||||
window.navigateTo(`/${networks[i].abbreviation}`)
|
||||
}
|
||||
})
|
||||
.cursor("default")
|
||||
@@ -41,7 +65,7 @@ class Sidebar extends Shadow {
|
||||
.borderRight("1px solid var(--accent)")
|
||||
.zIndex(3)
|
||||
.onEvent("themechange", () => {
|
||||
console.log("change")
|
||||
console.log("why is this needed smg")
|
||||
this.rerender()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"fs": "/_/code/ws/shim/fs.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="/_/code/quill.js"></script>
|
||||
<script src="/_/code/zod.js"></script>
|
||||
<script type="module" src="75820185/index.js"></script>
|
||||
|
||||
@@ -1,118 +1,149 @@
|
||||
import Socket from "/_/code/ws/Socket.js"
|
||||
import "./Home.js"
|
||||
|
||||
import util from "./util.js"
|
||||
window.util = util
|
||||
|
||||
window.Socket = new Socket()
|
||||
let Global = class {
|
||||
Socket = new Socket()
|
||||
profile = null
|
||||
currentNetwork = ""
|
||||
currentApp = ""
|
||||
util = util
|
||||
|
||||
window.currentNetwork = ""
|
||||
window.currentApp = ""
|
||||
|
||||
async function openNetworkAndApp() {
|
||||
|
||||
if(window.currentNetwork !== networkFromPath()) {
|
||||
window.currentNetwork = networkFromPath()
|
||||
const event = new CustomEvent('networkchanged', {
|
||||
detail: { name: currentNetwork }
|
||||
});
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
if(!window.currentNetwork.data) {
|
||||
let appData = await fetch("/app/orgdata/" + window.profile.networks[0].id, {method: "GET"})
|
||||
let json = await appData.json()
|
||||
window.currentNetwork.data = json
|
||||
}
|
||||
|
||||
if(window.currentApp !== appFromPath()) {
|
||||
window.currentApp = appFromPath()
|
||||
openApp = function(appName) {
|
||||
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
||||
let parts = window.location.pathname.split('/').filter(Boolean);
|
||||
let newPath = "/" + parts[0] + "/" + appUrl
|
||||
window.navigateTo(newPath)
|
||||
const event = new CustomEvent('appchange', {
|
||||
detail: { name: window.currentApp }
|
||||
detail: { name: appName }
|
||||
});
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
if(window.currentNetwork) { // 2 navigates fire on load: 1 initial, and one after the org redirect
|
||||
document.title = `${window.currentNetwork.abbreviation} | Parchment`
|
||||
async fetchAppData() {
|
||||
let personalSpace = this.currentNetwork === this.profile
|
||||
let appData = await fetch(`/app/${personalSpace ? "my" : "org"}data/` + this.currentNetwork.id, {method: "GET"})
|
||||
let json = await appData.json()
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("navigate", openNetworkAndApp)
|
||||
onNavigate = async () => {
|
||||
|
||||
window.openApp = function(appName) {
|
||||
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
||||
let parts = window.location.pathname.split('/').filter(Boolean);
|
||||
let newPath = "/" + parts[0] + "/" + appUrl
|
||||
window.navigateTo(newPath)
|
||||
const event = new CustomEvent('appchange', {
|
||||
detail: { name: appName }
|
||||
});
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
let selectedNetwork = this.networkFromPath()
|
||||
let selectedApp = this.appFromPath()
|
||||
|
||||
window.networkFromPath = function () {
|
||||
const pathname = window.location.pathname;
|
||||
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
||||
let networks = window.profile?.networks
|
||||
for(let i = 0; i < networks.length; i++) {
|
||||
let network = networks[i]
|
||||
if(network.abbreviation === firstSegment) {
|
||||
return network
|
||||
if(!selectedNetwork) {
|
||||
if(this.profile.networks.length > 0) {
|
||||
let path = `/${this.getDefaultNetworkName()}/${this.getDefaultAppName()}`
|
||||
history.replaceState({}, '', path)
|
||||
}
|
||||
} else if(!selectedApp) {
|
||||
if(this.currentNetwork === window.profile) {
|
||||
history.replaceState({}, '', `${window.location.pathname}/${window.profile.apps[0]}`)
|
||||
} else {
|
||||
history.replaceState({}, '', `${window.location.pathname}/${this.getDefaultAppName()}`)
|
||||
}
|
||||
}
|
||||
|
||||
selectedNetwork = this.networkFromPath()
|
||||
selectedApp = this.appFromPath()
|
||||
|
||||
let networkChanged = this.currentNetwork !== selectedNetwork
|
||||
let appChanged = this.currentApp !== selectedApp
|
||||
if(networkChanged) {
|
||||
this.currentNetwork = selectedNetwork
|
||||
this.currentApp = selectedApp
|
||||
const event = new CustomEvent('networkchange', {
|
||||
detail: { name: this.currentNetwork }
|
||||
});
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
if(!this.currentNetwork.data) {
|
||||
this.currentNetwork.data = await this.fetchAppData()
|
||||
}
|
||||
|
||||
if(appChanged && !networkChanged) {
|
||||
this.currentApp = selectedApp
|
||||
const event = new CustomEvent('appchange', {
|
||||
detail: { name: this.currentApp }
|
||||
});
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
document.title = (this.currentNetwork === this.profile) ? "Parchment" : `${this.currentNetwork.abbreviation} | Parchment`
|
||||
}
|
||||
|
||||
setCurrentNetworkAndApp() {
|
||||
this.currentNetwork = this.networkFromPath()
|
||||
|
||||
}
|
||||
|
||||
getDefaultNetworkName() {
|
||||
let defaultNetwork = this.profile.networks[0]
|
||||
return defaultNetwork.abbreviation
|
||||
}
|
||||
|
||||
getDefaultAppName() {
|
||||
let defaultNetwork = this.profile.networks[0]
|
||||
return defaultNetwork.apps[0].toLowerCase()
|
||||
}
|
||||
|
||||
networkFromPath = function () {
|
||||
const pathname = window.location.pathname;
|
||||
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
||||
if(firstSegment === "my") {
|
||||
return this.profile
|
||||
} else {
|
||||
let networks = this.profile.networks
|
||||
for(let i = 0; i < networks.length; i++) {
|
||||
let network = networks[i]
|
||||
if(network.abbreviation === firstSegment) {
|
||||
return network
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.appFromPath = function() {
|
||||
const pathname = window.location.pathname;
|
||||
const segments = pathname.split('/').filter(Boolean);
|
||||
const secondSegment = segments[1] || "";
|
||||
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
||||
return capitalized
|
||||
}
|
||||
appFromPath = function() {
|
||||
const pathname = window.location.pathname;
|
||||
const segments = pathname.split('/').filter(Boolean);
|
||||
const secondSegment = segments[1] || ""
|
||||
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
||||
return capitalized
|
||||
}
|
||||
|
||||
async function getProfile() {
|
||||
try {
|
||||
const res = await fetch("/profile", {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
async getProfile() {
|
||||
try {
|
||||
const res = await fetch("/profile", {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error("Failed to fetch profile");
|
||||
if (!res.ok) throw new Error("Failed to fetch profile");
|
||||
|
||||
const profile = await res.json();
|
||||
console.log("getProfile: ", profile);
|
||||
window.profile = profile
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const profile = await res.json();
|
||||
console.log("getProfile: ", profile);
|
||||
this.profile = profile
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
window.addEventListener("navigate", this.onNavigate)
|
||||
|
||||
this.getProfile().then(async () => {
|
||||
|
||||
await this.onNavigate()
|
||||
|
||||
Home()
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getInitialNetworkPath() {
|
||||
let path = ""
|
||||
let defaultNetwork = window.profile.networks[0]
|
||||
|
||||
if(!networkFromPath()) {
|
||||
path += (defaultNetwork.abbreviation + "/")
|
||||
}
|
||||
|
||||
if(!appFromPath()) {
|
||||
let defaultApp = defaultNetwork.apps[0]
|
||||
path += defaultApp.toLowerCase()
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
getProfile().then(async () => {
|
||||
|
||||
if(window.profile.networks.length > 0) {
|
||||
let path = getInitialNetworkPath()
|
||||
window.navigateTo(path)
|
||||
}
|
||||
|
||||
Home()
|
||||
})
|
||||
window.global = new Global()
|
||||
@@ -1,62 +0,0 @@
|
||||
class Connection {
|
||||
connectionTries = 0
|
||||
ws;
|
||||
linkCreated;
|
||||
wsStatus;
|
||||
|
||||
constructor(receiveCB) {
|
||||
this.init()
|
||||
this.receiveCB = receiveCB
|
||||
}
|
||||
|
||||
init() {
|
||||
if(window.location.hostname.includes("local")) {
|
||||
this.ws = new WebSocket("ws://" + window.location.host)
|
||||
} else {
|
||||
this.ws = new WebSocket("wss://" + window.location.hostname + window.location.pathname)
|
||||
}
|
||||
this.ws.addEventListener('open', () => {
|
||||
this.connectionTries = 0
|
||||
console.log("Websocket connection established.");
|
||||
this.ws.addEventListener('message', this.receiveCB)
|
||||
});
|
||||
this.ws.addEventListener("close", () => {
|
||||
this.checkOpen();
|
||||
console.log('Websocket Closed')
|
||||
})
|
||||
}
|
||||
|
||||
async checkOpen() {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
return true
|
||||
} else {
|
||||
await this.sleep(this.connectionTries < 20 ? 5000 : 60000)
|
||||
this.connectionTries++
|
||||
console.log('Reestablishing connection')
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
sleep = (time) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
send = (msg) => {
|
||||
console.log("sending")
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(msg);
|
||||
}
|
||||
else if(this.connectionTries === 0) {
|
||||
setTimeout(() => {
|
||||
this.send(msg)
|
||||
}, 100)
|
||||
}
|
||||
else {
|
||||
console.error('No websocket connection: Cannot send message');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Connection
|
||||
@@ -1,45 +0,0 @@
|
||||
import Connection from "./Connection.js";
|
||||
|
||||
export default class Socket {
|
||||
connection;
|
||||
disabled = true;
|
||||
requestID = 1;
|
||||
pending = new Map();
|
||||
|
||||
constructor() {
|
||||
this.connection = new Connection(this.receive);
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
if(this.connection.checkOpen()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
send(msg) {
|
||||
return new Promise(resolve => {
|
||||
const id = (++this.requestID).toString();
|
||||
this.pending.set(id, resolve);
|
||||
this.connection.send(JSON.stringify({ id, ...msg }));
|
||||
});
|
||||
}
|
||||
|
||||
receive = (event) => {
|
||||
const msg = JSON.parse(event.data);
|
||||
if (msg.id && this.pending.has(msg.id)) {
|
||||
this.pending.get(msg.id)(msg);
|
||||
this.pending.delete(msg.id);
|
||||
return;
|
||||
} else {
|
||||
this.onBroadcast(msg)
|
||||
}
|
||||
}
|
||||
|
||||
onBroadcast(msg) {
|
||||
window.dispatchEvent(new CustomEvent(msg.event, {
|
||||
detail: msg.msg
|
||||
}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user