Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
|
4091020069 | ||
|
c569423e65 | ||
|
807de742a0 | ||
|
b2b8f18bf3 | ||
|
88f6644518 | ||
|
9413862186 | ||
|
a0dc1d5715 | ||
|
c7c69a8c90 |
9 changed files with 1730 additions and 0 deletions
1
pizzicore/.gitignore
vendored
1
pizzicore/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
pizzicore.env
|
pizzicore.env
|
||||||
.*.sw[po]
|
.*.sw[po]
|
||||||
|
*.dbm.db
|
||||||
|
|
23
pizzicore/pages/spa.html
Normal file
23
pizzicore/pages/spa.html
Normal 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>
|
||||||
|
|
|
@ -214,3 +214,7 @@ async def root_page():
|
||||||
@app.get("/prenota")
|
@app.get("/prenota")
|
||||||
async def prenota_page():
|
async def prenota_page():
|
||||||
return await get_page("pages/prenotati.html")
|
return await get_page("pages/prenotati.html")
|
||||||
|
|
||||||
|
@app.get("/new")
|
||||||
|
async def prenota_page():
|
||||||
|
return await get_page("pages/spa.html")
|
||||||
|
|
41
pizzicore/static/js/spa.js
Normal file
41
pizzicore/static/js/spa.js
Normal 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')
|
15
pizzicore/static/js/vue.esm-browser.min.js
vendored
Normal file
15
pizzicore/static/js/vue.esm-browser.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1461
pizzicore/static/js/vuex.esm-browser.js
Normal file
1461
pizzicore/static/js/vuex.esm-browser.js
Normal file
File diff suppressed because it is too large
Load diff
81
pizzicore/static/vue/counter.js
Normal file
81
pizzicore/static/vue/counter.js
Normal 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)
|
||||||
|
}
|
52
pizzicore/static/vue/counterlist.js
Normal file
52
pizzicore/static/vue/counterlist.js
Normal 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;
|
||||||
|
}
|
||||||
|
|
52
pizzicore/static/vue/userlogin.js
Normal file
52
pizzicore/static/vue/userlogin.js
Normal 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')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue