Compare commits

...

8 commits

Author SHA1 Message Date
boyska
4091020069 style 2022-08-21 01:09:51 +02:00
boyska
c569423e65 style 2022-08-20 20:07:15 +02:00
boyska
807de742a0 si può mandare avanti il contatore! 2022-08-20 19:46:55 +02:00
boyska
b2b8f18bf3 ignore 2022-08-20 19:20:27 +02:00
boyska
88f6644518 add Vuex to project, refactor, WIP user login 2022-08-20 19:19:35 +02:00
boyska
9413862186 vue webui autodetects queue_num 2022-08-20 17:52:55 +02:00
boyska
a0dc1d5715 vue fa meglio 2022-08-20 17:15:09 +02:00
boyska
c7c69a8c90 vue rewrite start 2022-08-20 16:48:26 +02:00
9 changed files with 1730 additions and 0 deletions

View file

@ -1,2 +1,3 @@
pizzicore.env
.*.sw[po]
*.dbm.db

23
pizzicore/pages/spa.html Normal file
View file

@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<title>Eliminacode</title>
<style>
.counter {
border: 1px solid #ccc;
margin: 1em 0;
padding: 1em 0.2em;
font-size: 8vw;
font-family: sans-serif;
}
</style>
</head>
<body data-cid="0">
<div id="app">
</div>
<script type="module" src="/static/js/spa.js"></script>
</body>
</html>

View file

@ -214,3 +214,7 @@ async def root_page():
@app.get("/prenota")
async def prenota_page():
return await get_page("pages/prenotati.html")
@app.get("/new")
async def prenota_page():
return await get_page("pages/spa.html")

View file

@ -0,0 +1,41 @@
import { createApp, defineAsyncComponent } from '/static/js/vue.esm-browser.min.js'
import { createStore } from '/static/js/vuex.esm-browser.js'
// Create a new store instance.
const store = createStore({
state () {
return {
loggedIn: false,
username: '',
password: '',
}
},
mutations: {
logIn(state, payload) {
state.loggedIn = true
state.username = payload.username
state.password = payload.password
},
logOut(state) {
state.loggedIn = false
}
},
devtools: false,
})
var app = createApp({
components: {
'CounterList': defineAsyncComponent( () => import('/static/vue/counterlist.js') ),
'UserLogin': defineAsyncComponent( () => import('/static/vue/userlogin.js') ),
},
template: ` <CounterList></CounterList>
<UserLogin></UserLogin>
`
})
app.use(store)
app.mount('#app')

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,81 @@
const template = `
<div class="counter">Fila {{queue_desc}}: <div class="counter-number">{{counter}}</div>
<div v-if="loggedIn"><button @click="callNext">Prossimo</button></div></div>
`
export default {
props: ["queue_num"],
data() {
var me = this;
do_websocket(parseInt(me.queue_num, 10), function(new_value) {
me.counter = new_value
})
return { counter: -1 }
},
template: template,
computed: {
queue_desc: function() {
return printToLetter(parseInt(this.queue_num, 10) + 1)
},
loggedIn() {
return this.$store.state.loggedIn
}
},
methods: {
callNext() {
let headers = new Headers()
let username = this.$store.state.username
let password = this.$store.state.password
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password))
fetch('/v1/counter/' + this.queue_num + '/increment', {method: 'POST', headers: headers})
}
}
}
function get_url(cid)
{
var url = "";
if(window.location.protocol == "http:") {
url += "ws://"
} else {
url = "wss://"
}
url += window.location.host + '/v1/ws/counter/';
url += cid
return url;
}
function do_websocket(cid, cb_on_new_value)
{
const socket = new WebSocket(get_url(cid));
socket.onmessage = function(evt) {
var msg = JSON.parse(evt.data)
cb_on_new_value(msg.value)
}
socket.onclose = function() {
setTimeout(do_websocket, 3000)
}
socket.onerror = socket.onclose
}
/* thanks, https://stackoverflow.com/a/60033403 */
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function printToLetter(number, recursive){
number--
if(number < 0) {
if(recursive === true) {
return alphabet[alphabet.length - 1]
} else {
return 'ø'
}
}
if(number < alphabet.length) {
return alphabet[number]
}
var remainder = number % alphabet.length
var quotient = Math.floor((number-1)/alphabet.length)
return printToLetter(quotient, true) + printToLetter(remainder, true)
}

View file

@ -0,0 +1,52 @@
import { defineAsyncComponent } from '/static/js/vue.esm-browser.min.js'
const template = `
<div class="counters">
<CounterController v-for="q in queues" :queue_num="q"></CounterController>
</div>
`
export default {
template: template,
components: {
'CounterController': defineAsyncComponent( () => import('/static/vue/counter.js') ),
},
data() {
return {
queue_count: 0,
}
},
mounted: function () {
this.updateGlobalProperties()
},
methods: {
updateGlobalProperties() {
var me = this
fetch('/v1/counter/')
.then((response) => response.json())
.then(function(data) {
me.queue_count = data.counters
})
}
},
computed: {
queues() {
return range(0, this.queue_count-1)
}
},
}
function range(start, end) {
var ans = [];
for (let i = start; i <= end; i++) {
ans.push(i);
}
return ans;
}

View file

@ -0,0 +1,52 @@
const template = `
<div v-if="!loggedIn">
<input name="username" :value="username" />
<input name="password" type="password" :value="password" />
<button @click="checkLogin" >Login</button>
</div>
<div v-else>
<button @click="logout">Logout</button>
</div>
`
export default {
data() {
return { }
},
computed: {
loggedIn(){ return this.$store.state.loggedIn },
username(){ return this.$store.state.username },
password(){ return this.$store.state.password },
},
template: template,
methods: {
checkLogin: function() {
var username = document.querySelector('input[name=username]', this.$el).value
var password = document.querySelector('input[name=password]', this.$el).value
let $store = this.$root.$store
let headers = new Headers()
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password))
fetch('/v1/whoami', {method: 'GET', headers: headers})
.then(function(response) {
if(response.ok) {
console.info("Login OK")
$store.commit({
type: 'logIn',
username: username,
password: password
})
} else {
console.warn("Login error")
// XXX: animate some form of error
}
})
},
logout: function() {
this.$root.$store.commit('logOut')
},
}
}