group code popup
Sonarqube Scanner / Prepare environment (push) Successful in 6s
Sonarqube Scanner / Build and test (push) Successful in 27s
Sonarqube Scanner / SonarQube analysis (push) Failing after 1m14s
Sonarqube Scanner / Deploy to Server (push) Successful in 10s

This commit is contained in:
Florian Zumpe
2026-10-18 17:24:41 +02:00
parent 31768ae907
commit 0e4cdfbd54
18 changed files with 400 additions and 49 deletions
+44 -8
View File
@@ -8,7 +8,7 @@ globalThis.Wegwichtel ??= {};
entry: 'group-entry', invitation: 'group-invitation', code: 'group-code', join: 'group-join',
edit: 'group-edit', expiry: 'group-expiry'
};
const codeLength = 8;
const codeLength = 5;
const wheelStep = 52;
const revisions = new Map();
let selection = [];
@@ -43,6 +43,7 @@ globalThis.Wegwichtel ??= {};
function errorMessage(error) {
if (error.reason === 'group-limit') return t('error.limit');
if (error.reason === 'group-full') return t('error.full');
if (error.reason === 'group-editing') return t('code-wait');
if (error.status === 423) return ns.I18n.t('point-locks.busy');
if (error.status === 429) return t('error.rate');
if (error.status === 404) return t('error.code');
@@ -167,6 +168,19 @@ globalThis.Wegwichtel ??= {};
if (!element(ids.dialog).open) element(ids.dialog).showModal();
}
let invitationPolling = false;
async function refreshInvitation() {
const group = currentGroup;
if (!group || invitationPolling || !element(ids.dialog).open || element(ids.invitation).hidden) return;
invitationPolling = true;
try {
const payload = await request(`/${group.id}/invitation`);
if (currentGroup?.id !== group.id || !element(ids.dialog).open || element(ids.invitation).hidden) return;
if (payload.code) showInvitation(payload);
element(ids.status).textContent = payload.busy && payload.expired ? t('code-wait') : '';
} catch { /* Keep the invitation visible; expiry still applies on the server. */ }
finally { invitationPolling = false; }
}
async function edit(group) {
element(ids.dialog).close();
await ns.EditorUi.openGroup(group.route);
@@ -244,18 +258,34 @@ globalThis.Wegwichtel ??= {};
function shareButton(action) {
const result = document.createElement('button');
result.type = 'button';
result.className = 'editor-icon-button group-pair';
result.className = 'editor-icon-button';
result.dataset.editorAction = action;
result.title = t('share');
result.setAttribute('aria-label', t('share'));
for (const value of ['🐦', '🪨']) {
const image = picture(ns.GroupSymbols.get(value));
image.alt = '';
result.appendChild(image);
}
result.setAttribute('aria-haspopup', 'dialog');
result.textContent = '👥';
return result;
}
let shareDecision = null;
function confirmShare(name) {
if (shareDecision) return Promise.resolve(false);
const dialog = element('group-share-dialog');
element('group-share-route').textContent = name;
element('group-share-pictures').replaceChildren(...['🐦', '🪨'].map(value => picture(ns.GroupSymbols.get(value))));
return new Promise(resolve => {
shareDecision = resolve;
dialog.showModal();
});
}
function finishShare(accepted) {
const resolve = shareDecision;
shareDecision = null;
element('group-share-dialog').close();
resolve?.(accepted);
}
function headersFor(path) {
const id = /^\/routes\/(\d+)(?:\/|$)/.exec(path)?.[1];
return id && revisions.has(id) ? { 'If-Match': String(revisions.get(id)) } : {};
@@ -268,6 +298,12 @@ globalThis.Wegwichtel ??= {};
}
function init() {
globalThis.setInterval?.(() => { void refreshInvitation(); }, 30_000);
activate(element('group-share-start'), () => finishShare(true));
activate(element('group-share-close'), () => finishShare(false));
element('group-share-dialog').addEventListener('close', () => {
const resolve = shareDecision; shareDecision = null; resolve?.(false);
});
document.addEventListener('wegwichtel:point-drafts-changed', () => { void renderPending(); void ns.StorageUsage?.refresh(); });
element(ids.dialog).addEventListener('cancel', () => { dialogGeneration += 1; });
element(ids.dialog).addEventListener('close', () => { dialogGeneration += 1; });
@@ -292,7 +328,7 @@ globalThis.Wegwichtel ??= {};
activate(element(ids.edit), () => guarded(() => edit(currentGroup)));
}
ns.Groups = Object.freeze({ share, shareButton, refresh, headersFor, observe });
ns.Groups = Object.freeze({ share, shareButton, confirmShare, refresh, refreshInvitation, headersFor, observe });
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true });
else init();
}(globalThis.Wegwichtel));