Profile + Edit Bio + Logout + styling
- Added handler for editing bio to handlers.js - Added openProfile() and closeProfile() buttons in AppWindowContainer (Profile page is global) - Added Logout and Profile functionality to Sidebar.js - SidebarItem(text).onClick() fires twice, unable to resolve - Adjust Login page styling - Added onLogout() to index.js (removes auth_token) - Added Profile.js, displays user's profile picture (placeholder), name, and bio. User can edit bio. - Added removeAuthToken() to util.js - Added /signout to vite config
This commit is contained in:
@@ -22,7 +22,7 @@ class AuthPage extends Shadow {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedPage = 2 // 1 == login, 2 == signup
|
selectedPage = 1 // 1 == login, 2 == signup
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
@@ -60,7 +60,7 @@ class AuthPage extends Shadow {
|
|||||||
.color("var(--text)")
|
.color("var(--text)")
|
||||||
.horizontalAlign("center")
|
.horizontalAlign("center")
|
||||||
.margin("auto")
|
.margin("auto")
|
||||||
.marginTop(1, em)
|
.marginTop(7.5, em)
|
||||||
.marginBottom(0, em)
|
.marginBottom(0, em)
|
||||||
.gap(0.5, em)
|
.gap(0.5, em)
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,6 @@ class Signup extends Shadow {
|
|||||||
render() {
|
render() {
|
||||||
form(() => {
|
form(() => {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
input("Email", "70vw")
|
|
||||||
.attr({ name: "email", type: "email" })
|
|
||||||
.margin("auto")
|
|
||||||
.marginVertical(1, em)
|
|
||||||
.padding(1, em)
|
|
||||||
.styles(this.inputStyles)
|
|
||||||
input("First Name", "70vw")
|
input("First Name", "70vw")
|
||||||
.attr({ name: "firstName", type: "text" })
|
.attr({ name: "firstName", type: "text" })
|
||||||
.margin("auto")
|
.margin("auto")
|
||||||
@@ -43,6 +37,12 @@ class Signup extends Shadow {
|
|||||||
.marginVertical(1, em)
|
.marginVertical(1, em)
|
||||||
.padding(1, em)
|
.padding(1, em)
|
||||||
.styles(this.inputStyles)
|
.styles(this.inputStyles)
|
||||||
|
input("Email", "70vw")
|
||||||
|
.attr({ name: "email", type: "email" })
|
||||||
|
.margin("auto")
|
||||||
|
.marginVertical(1, em)
|
||||||
|
.padding(1, em)
|
||||||
|
.styles(this.inputStyles)
|
||||||
input("Password", "70vw")
|
input("Password", "70vw")
|
||||||
.attr({ name: "password", type: "password" })
|
.attr({ name: "password", type: "password" })
|
||||||
.margin("auto")
|
.margin("auto")
|
||||||
|
|||||||
120
src/Profile/Profile.js
Normal file
120
src/Profile/Profile.js
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import server from "../_/code/bridge/serverFunctions";
|
||||||
|
|
||||||
|
css(`
|
||||||
|
profile- textarea::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile- textarea::-webkit-scrollbar-thumb {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile- textarea::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
class Profile extends Shadow {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.profile = global.profile
|
||||||
|
this.bioText = global.profile.bio ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
ZStack(() => {
|
||||||
|
p("X")
|
||||||
|
.color("var(--quillred")
|
||||||
|
.fontSize(4, em)
|
||||||
|
.position("absolute")
|
||||||
|
.top(0.5, rem)
|
||||||
|
.right(2, rem)
|
||||||
|
.zIndex(1001)
|
||||||
|
.onClick(() => {
|
||||||
|
$("appwindowcontainer-").closeProfile()
|
||||||
|
})
|
||||||
|
|
||||||
|
form(() => {
|
||||||
|
VStack(() => {
|
||||||
|
HStack(() => { }) // Profile Image placeholder
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.height(10, em)
|
||||||
|
.width(10, em)
|
||||||
|
.paddingHorizontal(0.5, em)
|
||||||
|
.border("1px solid var(--accent)")
|
||||||
|
.borderRadius(100, pct)
|
||||||
|
.background("var(--darkaccent)")
|
||||||
|
|
||||||
|
h1(this.profile.first_name + " " + this.profile.last_name)
|
||||||
|
.color("var(--headertext")
|
||||||
|
.width(70, pct)
|
||||||
|
.textAlign("center")
|
||||||
|
|
||||||
|
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")
|
||||||
|
.padding(1, em)
|
||||||
|
.fontSize(1.1, em)
|
||||||
|
.borderRadius(12, px)
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.color("var(--text)")
|
||||||
|
.border("1px solid var(--accent)")
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.marginVertical(0.75, em)
|
||||||
|
})
|
||||||
|
.horizontalAlign("center")
|
||||||
|
.marginTop(5, em)
|
||||||
|
})
|
||||||
|
.onSubmit(async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const newBio = new FormData(e.target).get("bioinput");
|
||||||
|
if (newBio.trim() !== this.profile.bio.trim()) {
|
||||||
|
const result = await server.editBio(newBio, this.profile.id)
|
||||||
|
const { bio, updated_at } = result.data
|
||||||
|
global.profile.bio = bio
|
||||||
|
global.profile.updated_at = updated_at
|
||||||
|
this.profile = global.profile
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.backgroundColor("var(--main)")
|
||||||
|
.overflowX("hidden")
|
||||||
|
.height(window.visualViewport.height - 20, px)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.width(100, pct)
|
||||||
|
.position("fixed")
|
||||||
|
.top(20, px)
|
||||||
|
.zIndex(1000)
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register(Profile)
|
||||||
@@ -42,6 +42,10 @@ const handlers = {
|
|||||||
async getJobs(networkId) {
|
async getJobs(networkId) {
|
||||||
return global.db.jobs.getByNetwork(networkId)
|
return global.db.jobs.getByNetwork(networkId)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async editBio(newBio, userId) {
|
||||||
|
return global.db.members.editBio(newBio, userId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default handlers
|
export default handlers
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import "./AppWindow.js"
|
import "./AppWindow.js"
|
||||||
|
import "../Profile/Profile.js"
|
||||||
|
|
||||||
class AppWindowContainer extends Shadow {
|
class AppWindowContainer extends Shadow {
|
||||||
|
isProfileOpen = false
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
ZStack(() => {
|
ZStack(() => {
|
||||||
|
|
||||||
@@ -11,12 +14,26 @@ class AppWindowContainer extends Shadow {
|
|||||||
})
|
})
|
||||||
.width(100, pct)
|
.width(100, pct)
|
||||||
.gap(0)
|
.gap(0)
|
||||||
|
|
||||||
|
if (this.isProfileOpen) {
|
||||||
|
Profile()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.height(100, pct)
|
.height(100, pct)
|
||||||
.overflowY("hidden")
|
.overflowY("hidden")
|
||||||
.display("flex")
|
.display("flex")
|
||||||
.position("relative")
|
.position("relative")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openProfile() {
|
||||||
|
this.isProfileOpen = true
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
closeProfile() {
|
||||||
|
this.isProfileOpen = false
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register(AppWindowContainer)
|
register(AppWindowContainer)
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import util from "../util"
|
||||||
|
|
||||||
class Sidebar extends Shadow {
|
class Sidebar extends Shadow {
|
||||||
|
|
||||||
SidebarItem(text) {
|
SidebarItem(text) {
|
||||||
@@ -7,10 +9,18 @@ class Sidebar extends Shadow {
|
|||||||
.fontFamily("Sedan SC")
|
.fontFamily("Sedan SC")
|
||||||
.marginLeft(2, em)
|
.marginLeft(2, em)
|
||||||
.fontStyle("italic")
|
.fontStyle("italic")
|
||||||
.onClick(function () {
|
.onClick(function () { // BUG -- Fires twice every time
|
||||||
if(this.innerText === "Home") {
|
if(this.innerText === "Home") {
|
||||||
window.navigateTo("/")
|
window.navigateTo("/")
|
||||||
return
|
return
|
||||||
|
} else if (this.innerText === "Logout") {
|
||||||
|
$("sidebar-").close()
|
||||||
|
global.onLogout()
|
||||||
|
return
|
||||||
|
} else if (this.innerText === "Profile") {
|
||||||
|
$("appwindowcontainer-").openProfile()
|
||||||
|
$("sidebar-").close()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
window.navigateTo(this.innerText.toLowerCase().replace(/\s+/g, ""))
|
window.navigateTo(this.innerText.toLowerCase().replace(/\s+/g, ""))
|
||||||
})
|
})
|
||||||
@@ -18,6 +28,7 @@ class Sidebar extends Shadow {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
|
this.SidebarItem("Profile")
|
||||||
this.SidebarItem("Home")
|
this.SidebarItem("Home")
|
||||||
this.SidebarItem("Map")
|
this.SidebarItem("Map")
|
||||||
this.SidebarItem("Logout")
|
this.SidebarItem("Logout")
|
||||||
@@ -35,6 +46,12 @@ class Sidebar extends Shadow {
|
|||||||
.zIndex(3)
|
.zIndex(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
if(this.style.right !== "-71vw") {
|
||||||
|
this.style.right = "-71vw"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
if(this.style.right === "-71vw") {
|
if(this.style.right === "-71vw") {
|
||||||
this.style.right = "0vw"
|
this.style.right = "0vw"
|
||||||
|
|||||||
10
src/index.js
10
src/index.js
@@ -150,6 +150,16 @@ let Global = class {
|
|||||||
// navigateTo("/")
|
// navigateTo("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onLogout() {
|
||||||
|
await util.removeAuthToken()
|
||||||
|
await fetch(`${util.HOST}/signout`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include"
|
||||||
|
});
|
||||||
|
this.profile = null
|
||||||
|
AuthPage()
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
window.addEventListener("navigate", this.onNavigate)
|
window.addEventListener("navigate", this.onNavigate)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ export default class util {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async removeAuthToken() {
|
||||||
|
await Preferences.remove({ key: 'auth_token'})
|
||||||
|
}
|
||||||
|
|
||||||
static cssVariable(value) {
|
static cssVariable(value) {
|
||||||
return getComputedStyle(document.documentElement)
|
return getComputedStyle(document.documentElement)
|
||||||
.getPropertyValue("--" + value)
|
.getPropertyValue("--" + value)
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ export default defineConfig({
|
|||||||
target: "http://localhost:10002",
|
target: "http://localhost:10002",
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
},
|
},
|
||||||
|
"/signout": {
|
||||||
|
target: "http://localhost:10002",
|
||||||
|
changeOrigin: true
|
||||||
|
},
|
||||||
"/profile": {
|
"/profile": {
|
||||||
target: "http://localhost:10002",
|
target: "http://localhost:10002",
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
|
|||||||
Reference in New Issue
Block a user