Minor js riorganization and dev setup enhancements

dev
Antonio De Lucreziis 3 years ago
parent 35ffa78c35
commit fb2db34a9b

@ -5,8 +5,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Posti DM</title>
<script type="module" src="./src/index.js"></script>
</head>
<body>
<nav>
@ -15,18 +13,18 @@
</div>
<div class="nav-group center">
<div class="nav-item">
<a href=".">Posti DM</a>
<a href="/">Posti DM</a>
</div>
</div>
<div class="nav-group right">
<div id="login-label" class="nav-item">
<a href="./login.html">Login</a>
<div id="nav-user" class="nav-group right">
<div class="nav-item login-label">
<a href="/login">Login</a>
</div>
<div id="logged-label" class="nav-item hidden">
<div class="nav-item hidden logged-label">
<!-- @username -->
</div>
<div id="logout-label" class="nav-item hidden">
<button id="logout-button">Logout</button>
<div class="nav-item hidden logout-label">
<button class="logout-button">Logout</button>
</div>
</div>
</nav>

@ -5,8 +5,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Posti DM</title>
<script type="module" src="./src/index.js"></script>
</head>
<body>
<nav>
@ -15,7 +13,7 @@
</div>
<div class="nav-group center">
<div class="nav-item">
<a href=".">Posti DM</a>
<a href="/">Posti DM</a>
</div>
</div>
</nav>
@ -32,6 +30,6 @@
<button id="button-login" class="fill-row gap-above-l">Login</button>
</div>
</main>
<script type="module" src="./src/pages/login.js"></script>
<script type="module" src="../src/pages/login.js"></script>
</body>
</html>

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Posti DM</title>
</head>
<body>
<nav>
<div class="nav-group left">
<div class="nav-item" id="clock">14:23</div>
</div>
<div class="nav-group center">
<div class="nav-item">
<a href="/">Posti DM</a>
</div>
</div>
<div class="nav-group right">
<div id="login-label" class="nav-item">
<a href="/login">Login</a>
</div>
<div id="logged-label" class="nav-item hidden">
<!-- @username -->
</div>
<div id="logout-label" class="nav-item hidden">
<button id="logout-button">Logout</button>
</div>
</div>
</nav>
<main></main>
<script type="module" src="../src/pages/orari.js"></script>
</body>
</html>

@ -0,0 +1,103 @@
import './style.scss'
/**
* `BASE_URL` string from environment file without final slash (for more readable interpolated strings)
*/
export const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, '')
const NotCached = Symbol('not cached')
export const User = {
_user: NotCached,
async getLogged() {
if (User._user === NotCached) {
console.log('Caching user data...')
const res = await fetch(`${BASE_URL}/api/user`)
const user = await res.json()
User._user = user
}
return User._user
},
async login(username, password) {
try {
const response = await fetch(`${BASE_URL}/api/login`, {
method: 'POST',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
})
if (!response.ok) {
return { error: await response.text() }
}
// If successful redirect to homepage
location.href = `${BASE_URL}/`
} catch (e) {
return { error: e }
}
},
async logout() {
await fetch(`${BASE_URL}/api/logout`, { method: 'POST' })
location.href = `${BASE_URL}/`
},
}
export function createRoomEventStream(roomId) {
return new EventSource(`${BASE_URL}/api/room_events?id=${roomId}`)
}
export const Database = {
async getSeats(roomId) {
const seatList = await (await fetch(`${BASE_URL}/api/room/seats?id=${roomId}`)).json()
const seats = {}
seatList.forEach(seat => {
seats[seat.id] = seat
})
return seats
},
async occupySeat(seatId) {
const response = await fetch(`${BASE_URL}/api/seat/occupy?id=${seatId}`, {
method: 'POST',
})
if (!response.ok) {
throw new Error(await response.text())
}
await response.json()
},
async leaveSeat(seatId) {
const response = await fetch(`${BASE_URL}/api/seat/leave?id=${seatId}`, {
method: 'POST',
})
if (!response.ok) {
throw new Error(await response.text())
}
await response.json()
},
}
// Always append BASE_URL to all <a> links in the page.
document.querySelectorAll('a').forEach($a => {
const url = $a.getAttribute('href')
let newUrl = BASE_URL + url
if (import.meta.env.MODE === 'development') {
if (newUrl.endsWith('/')) newUrl += 'index'
newUrl += '.html'
}
$a.href = newUrl
})

@ -47,5 +47,5 @@ export function createGridLineCanvas($roomGrid) {
const render = () => renderGridLinesCanvas($canvas, [rows, cols])
window.addEventListener('resize', render)
render()
requestAnimationFrame(render)
}

@ -0,0 +1,40 @@
import { User } from '../common.js'
function elements(el) {
return {
elLoggedLabel: el.querySelector('.logged-label'),
elLoginLabel: el.querySelector('.login-label'),
elLogoutLabel: el.querySelector('.logout-label'),
elLogoutButton: el.querySelector('.logout-button'),
}
}
function setup(el) {
const { elLogoutButton } = elements(el)
elLogoutButton.addEventListener('click', () => User.logout())
}
function update(el, { user }) {
const { elLoggedLabel, elLoginLabel, elLogoutLabel } = elements(el)
elLoginLabel.classList.toggle('hidden', user)
const roleString =
user && user.permissions.length > 0 ? ` (${user.permissions.join(', ')})` : ''
elLoggedLabel.innerText = user ? `@${user.id}${roleString}` : ''
elLoggedLabel.classList.toggle('hidden', !user)
elLogoutLabel.classList.toggle('hidden', !user)
}
export function createNavUser(el) {
setup(el)
// Load current user
;(async () => {
const user = await User.getLogged()
update(el, { user })
})()
}

@ -1,8 +1,8 @@
import { BASE_URL, createRoomEventStream, Database, getLoggedUser } from '../index.js'
import { addTooltipElementListener, resetTooltip, setTooltipText } from './tooltip.js'
import { BASE_URL, createRoomEventStream, Database, User } from '../common'
import { addTooltipElementListener, setTooltipText } from './tooltip'
async function renderWidget(elSeatMap, seats) {
const user = await getLoggedUser()
const user = await User.getLogged()
Object.values(seats).forEach(seat => {
const { id, occupiedBy } = seat
@ -26,7 +26,7 @@ async function renderWidget(elSeatMap, seats) {
}
export async function createSeatWidget($roomGrid, roomId) {
const user = await getLoggedUser()
const user = await User.getLogged()
const elSeats = [...$roomGrid.querySelectorAll('[data-seat-id]')]
const elSeatMap = {}

@ -1,52 +0,0 @@
import './style.scss'
export const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, '')
let USER = false
export async function getLoggedUser() {
if (USER === false) {
console.log('Caching user data...')
USER = await (await fetch(`${BASE_URL}/api/user`)).json()
}
return USER
}
export function createRoomEventStream(roomId) {
return new EventSource(`${BASE_URL}/api/room_events?id=${roomId}`)
}
export const Database = {
async getSeats(roomId) {
const seatList = await (await fetch(`${BASE_URL}/api/room/seats?id=${roomId}`)).json()
const seats = {}
seatList.forEach(seat => {
seats[seat.id] = seat
})
return seats
},
async occupySeat(seatId) {
const response = await fetch(`${BASE_URL}/api/seat/occupy?id=${seatId}`, {
method: 'POST',
})
if (!response.ok) {
throw new Error(await response.text())
}
await response.json()
},
async leaveSeat(seatId) {
const response = await fetch(`${BASE_URL}/api/seat/leave?id=${seatId}`, {
method: 'POST',
})
if (!response.ok) {
throw new Error(await response.text())
}
await response.json()
},
}

@ -1,48 +1,30 @@
import { createGridLineCanvas } from '../components/gridlines.js'
import { BASE_URL, getLoggedUser } from '../index.js'
import { createSeatWidget } from '../components/seats-widget.js'
import { createClock } from '../components/clock.js'
import { attachTooltip } from '../components/tooltip.js'
import '../common'
const elClock = document.querySelector('#clock')
import { createGridLineCanvas } from '../components/grid-lines'
import { BASE_URL } from '../common'
import { createSeatWidget } from '../components/seats-widget'
import { createClock } from '../components/clock'
import { attachTooltip } from '../components/tooltip'
import { createNavUser } from '../components/nav-user.js'
const elLoggedLabel = document.querySelector('#logged-label')
const elLoginLabel = document.querySelector('#login-label')
const elLogoutLabel = document.querySelector('#logout-label')
const elClock = document.querySelector('#clock')
const elLogoutButton = document.querySelector('#logout-button')
const elNavUser = document.querySelector('#nav-user')
const elRoomGrid = document.querySelector('.room-grid')
async function logout() {
await fetch(`${BASE_URL}/api/logout`, { method: 'POST' })
location.href = `${BASE_URL}`
}
async function main() {
const urlSearchParams = new URLSearchParams(window.location.search)
const params = Object.fromEntries(urlSearchParams.entries())
console.log(params)
elLogoutButton.addEventListener('click', () => logout())
const user = await getLoggedUser()
if (user) {
elLoginLabel.classList.add('hidden')
elLoggedLabel.innerText =
'@' + user.id + (user.permissions.length > 0 ? ` (${user.permissions.join(', ')})` : '')
elLoggedLabel.classList.remove('hidden')
elLogoutLabel.classList.remove('hidden')
}
// Widgets
// createClock(elClock)
createGridLineCanvas(elRoomGrid)
createSeatWidget(elRoomGrid, 'aula-stud')
createNavUser(elNavUser)
// Use tooltips only on desktop
if (matchMedia('(pointer: fine)').matches) {
attachTooltip()

@ -1,4 +1,6 @@
import { BASE_URL, getLoggedUser } from '../index.js'
import '../common'
import { BASE_URL, User } from '../common'
//
// Page Element
@ -16,8 +18,7 @@ const elLoginButton = document.querySelector('#button-login')
//
let errorTimeoutHandle = null
function displayErrorString(e) {
function displayFormErrorMessage(e) {
if (errorTimeoutHandle) clearTimeout(errorTimeoutHandle)
elErrorString.classList.toggle('hidden', false)
elErrorString.innerText = e.toString()
@ -31,28 +32,10 @@ function displayErrorString(e) {
// Handle Login Button
//
async function login() {
try {
const response = await fetch(`${BASE_URL}/api/login`, {
method: 'POST',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: elLoginUsernameInput.value,
password: elLoginPasswordInput.value,
}),
})
if (!response.ok) {
displayErrorString(await response.text())
return
}
location.href = `${BASE_URL}/`
} catch (e) {
displayErrorString(e)
async function onLoginButtonClick() {
const res = await User.login(elLoginUsernameInput.value, elLoginPasswordInput.value)
if (res.error) {
displayFormErrorMessage(res.error)
}
}
@ -61,16 +44,17 @@ async function login() {
//
async function main() {
const user = await getLoggedUser()
console.log(user)
const user = await User.getLogged()
if (user) {
location.href = `${BASE_URL}/`
}
elLoginButton.addEventListener('click', () => login())
elLoginButton.addEventListener('click', () => {
onLoginButtonClick()
})
elLoginPasswordInput.addEventListener('keydown', e => {
if (e.key === 'Enter') login()
if (e.key === 'Enter') onLoginButtonClick()
})
elLoginUsernameInput.focus()

@ -0,0 +1 @@
import '../common'

@ -2,6 +2,7 @@ import { defineConfig, loadEnv } from 'vite'
import { resolve } from 'path'
export default defineConfig(({ mode }) => {
// Load environment variables with no prefixes
process.env = { ...process.env, ...loadEnv(mode, process.cwd(), '') }
console.log(`BASE_URL = "${process.env.BASE_URL}"`)
@ -12,7 +13,7 @@ export default defineConfig(({ mode }) => {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
login: resolve(__dirname, 'login.html'),
login: resolve(__dirname, 'login/index.html'),
},
},
},

Loading…
Cancel
Save