implement timer

This commit is contained in:
Joachim Lusiardi 2025-07-16 19:13:48 +02:00
parent 51a23f3317
commit 2777ddb25a
5 changed files with 105 additions and 22 deletions

40
app.py
View File

@ -10,8 +10,9 @@ load_dotenv() # Load environment variables from .env file
socketio = SocketIO()
def prepareRetroData(retroData, participantId):
def prepareRetroData(retroData, participantId, ttl=0):
preparedRetro = {
"remainingTime": ttl,
"extId": retroData["extId"],
"moods": retroData["moods"],
"participants": len(retroData["participants"]),
@ -52,6 +53,8 @@ def home():
@app.route("/create-retro")
def createRetro():
ext_id = str(uuid.uuid4())
duration = request.args.get("duration", 600)
newRetro = {
"extId": ext_id,
"participants": [],
@ -61,6 +64,7 @@ def createRetro():
"todo": [],
}
redis_client.set(f"retro_{ext_id}", json.dumps(newRetro))
redis_client.set(f"retrotimer_{ext_id}", "timer", ex=duration)
return redirect(url_for("performRetro", rExtId=ext_id, pExtId="0"))
@ -113,7 +117,8 @@ def handle_request_data(retroId, participantId):
# which retro are we connected to?
print("request_data", retroId, participantId)
retro = json.loads(redis_client.get(f"retro_{retroId}"))
emit("transmit_retro", json.dumps(prepareRetroData(retro, participantId)))
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit("transmit_retro", json.dumps(prepareRetroData(retro, participantId, ttl)))
@socketio.on("disconnect")
@ -136,8 +141,11 @@ def handle_mood_update(retroId, participantId, mood):
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)
@ -151,8 +159,12 @@ def handle_positiv_added(retroId, participantId, text):
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)
@ -166,8 +178,11 @@ def handle_negativ_added(retroId, participantId, text):
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)
@ -181,8 +196,11 @@ def handle_todo_added(retroId, participantId, text):
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)
@ -208,8 +226,11 @@ def handle_comment_removed(retroId, participantId, commentId):
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)
@ -231,8 +252,11 @@ def handle_comment_edited(retroId, participantId, commentId, text):
break
redis_client.set(f"retro_{retroId}", json.dumps(retro))
join_room(retroId)
ttl = redis_client.ttl(f"retrotimer_{retroId}")
emit(
"transmit_retro", json.dumps(prepareRetroData(retro, participantId)), to=retroId
"transmit_retro",
json.dumps(prepareRetroData(retro, participantId, ttl)),
to=retroId,
)

View File

@ -1,4 +0,0 @@
from app import app, db
with app.app_context():
db.create_all()

View File

@ -14,13 +14,26 @@
<div class="row">
<div class="col">
<h1>Willkommen beim Retrotool!</h1>
Starte eine <a href="{{ url_for('createRetro') }}">neue Retro</a>!
Starte eine <a id="starter" href="{{ url_for('createRetro') }}">neue Retro</a> mit <input id="duration" min="1" max="60"
type="number" size="3" value="10"> Minuten Zeit zur Eingabe der Punkte.
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q"
crossorigin="anonymous"></script>
</div>
</div>
</div>
<script type="importmap">
{
"imports": {
"socket.io-client": "https://cdn.socket.io/4.8.1/socket.io.esm.min.js"
}
}
</script>
<script type="module">
import { init_starter } from "/static/retro.js";
init_starter();
</script>
</body>
</html>

View File

@ -21,11 +21,24 @@
</div>
</div>
<div class="row">
<div class="col">
Teile folgenden link: <input type="email" class="form-control" id="exampleFormControlInput1"
value="{{url_for('joinRetro', extId=retro.extId, _external=True)}}" />
<button type="button" class="btn btn-primary"
onclick="var copyTextarea = document.getElementById('exampleFormControlInput1');copyTextarea.focus();copyTextarea.select();document.execCommand('copy')">Copy</button>
<div class="col-6">
<div class="card">
<h5 class="card-header">Einladungslink</h5>
<div class="card-body">
Teile folgenden link: <input type="email" class="form-control" id="exampleFormControlInput1"
value="{{url_for('joinRetro', extId=retro.extId, _external=True)}}" />
<button type="button" class="btn btn-primary"
onclick="var copyTextarea = document.getElementById('exampleFormControlInput1');copyTextarea.focus();copyTextarea.select();document.execCommand('copy')">Kopieren</button>
</div>
</div>
</div>
<div class="col-6" style="align-content: center;">
<div class="card" style="height: 100%;">
<h5 class="card-header">Verbleibende Zeit</h5>
<div class="card-body" style="align-content: center;">
<h1 id="timer" val="0"></h1>
</div>
</div>
</div>
</div>
<div class="row">
@ -34,7 +47,8 @@
<h5 class="card-header">Gut</h5>
<div class="card-body">
<textarea class="form-control" id="positivTextarea" rows="2"></textarea>
<button type="submit" class="btn btn-primary mb-3" id="positivButton">Add</button>
<button type="submit" class="btn btn-primary mb-3" id="positivButton"><i
class="bi bi-file-earmark-plus"></i></button>
</div>
</div>
<div id="goods" class="mb-3">
@ -45,7 +59,8 @@
<h5 class="card-header">Schlecht</h5>
<div class="card-body">
<textarea class="form-control" id="negativTextarea" rows="2"></textarea>
<button type="submit" class="btn btn-primary mb-3" id="negativButton">Add</button>
<button type="submit" class="btn btn-primary mb-3" id="negativButton"><i
class="bi bi-file-earmark-plus"></i></button>
</div>
</div>
<div id="bads" class="mb-3">
@ -56,7 +71,8 @@
<h5 class="card-header">ToDos</h5>
<div class="card-body">
<textarea class="form-control" id="todoTextarea" rows="2"></textarea>
<button type="submit" class="btn btn-primary mb-3" id="todoButton">Add</button>
<button type="submit" class="btn btn-primary mb-3" id="todoButton"><i
class="bi bi-file-earmark-plus"></i></button>
</div>
</div>
<div id="todos" class="mb-3">

View File

@ -36,8 +36,10 @@ class Retro {
good: Array<Comment>;
bad: Array<Comment>;
todo: Array<Comment>;
remainingTime: number;
constructor(data: object) {
this.remainingTime = data["remainingTime"];
this.extId = data["extId"];
this.participants = data["participants"];
this.moods = new Map();
@ -159,10 +161,23 @@ function create_or_update(comment: Comment, type: string) {
document.getElementById(cardContentId).innerHTML = comment.text;
}
function calc_time(seconds: number): string {
var minuteString = Math.floor(seconds / 60).toString();
if (minuteString.length == 1) {
minuteString = "0" + minuteString;
}
var secondsString = (seconds % 60).toString();
if (secondsString.length == 1) {
secondsString = "0" + secondsString;
}
return minuteString + ":" + secondsString;
}
function update_retro(retro: Retro, own_participant_id: string) {
// render number of participants
(document.getElementById('numberOfParticipants') as HTMLParagraphElement).textContent = retro.participants.toString();
(document.getElementById('timer') as HTMLDivElement).textContent = calc_time(Math.max(retro.remainingTime, 0));
(document.getElementById('timer') as HTMLDivElement).setAttribute("val", retro.remainingTime.toString())
// render all mood expressions
retro.moods.forEach(function (value: number, key: string) {
if (key == own_participant_id) {
@ -278,4 +293,23 @@ export function init_retro(_retroId: string, _participantId: string) {
update_retro(retro, participantId);
});
setInterval(function () {
var old = Number((document.getElementById('timer') as HTMLDivElement).getAttribute("val"));
var remaining = Math.max(old - 1, 0);
console.log(old, remaining);
(document.getElementById('timer') as HTMLDivElement).setAttribute("val", remaining.toString());
(document.getElementById('timer') as HTMLDivElement).textContent = calc_time(remaining);
}, 1000)
}
export function init_starter() {
const link = document.getElementById('starter')! as HTMLLinkElement;
link.addEventListener("click", function () {
const input = document.getElementById('duration')! as HTMLInputElement;
const duration: number = Number(input.value);
const link = document.getElementById('starter')! as HTMLLinkElement;
console.log(link.href);
link.href = link.href + "?duration=" + (duration * 60);
return false;
});
}