update: different colors for suggested rehersal and validated rehersal

This commit is contained in:
Nathan FONTEYNE 2026-08-11 11:44:42 +02:00
parent b056af78ac
commit a3d62200ce
10 changed files with 102 additions and 24 deletions

View file

@ -179,7 +179,14 @@ async function onRemoveFeed(feedId) {
}
}
async function loadSlotSettingsForm() {
function hostOptionsHtml(users, selectedId) {
const options = users.map(
(u) => `<option value="${u.id}"${u.id === selectedId ? ' selected' : ''}>${escapeHtml(u.name)}</option>`
);
return `<option value=""${selectedId ? '' : ' selected'}>(aucun)</option>${options.join('')}`;
}
async function loadSlotSettingsForm(users) {
const settings = await api.get('/api/calendar/settings');
const form = document.getElementById('slot-settings-form');
form.weekdayStart.value = settings.weekdayStart;
@ -190,6 +197,7 @@ async function loadSlotSettingsForm() {
form.concertStart.value = settings.concertStart;
form.concertEnd.value = settings.concertEnd;
form.rehearsalConfirmThreshold.value = settings.rehearsalConfirmThreshold;
form.rehearsalHostUserId.innerHTML = hostOptionsHtml(users, settings.rehearsalHostUserId);
}
async function onSaveSlotSettings(e) {
@ -207,6 +215,7 @@ async function onSaveSlotSettings(e) {
concertStart: form.concertStart.value,
concertEnd: form.concertEnd.value,
rehearsalConfirmThreshold: parseInt(form.rehearsalConfirmThreshold.value, 10),
rehearsalHostUserId: form.rehearsalHostUserId.value || null,
});
statusEl.textContent = 'Horaires enregistrés.';
} catch (err) {
@ -277,6 +286,14 @@ async function onSaveSlotSettings(e) {
n'est pas atteint ; elle passe ensuite en répétition confirmée (dans l'application et dans le
flux ICS).
</p>
<label>Hôte des répétitions ()
<select name="rehearsalHostUserId"></select>
</label>
<p class="note">
Si un hôte est désigné, une répétition ne peut être confirmée que si cette personne a elle-même
accepté le créneau sans elle, pas de lieu pour répéter. Choisissez « (aucun) » pour désactiver
cette contrainte.
</p>
<p class="note" id="slot-settings-status"></p>
<button type="submit">Enregistrer</button>
</form>
@ -310,7 +327,7 @@ async function onSaveSlotSettings(e) {
`;
document.getElementById('slot-settings-form').addEventListener('submit', onSaveSlotSettings);
document.getElementById('add-discord-webhook-form').addEventListener('submit', onAddDiscordWebhook);
await loadSlotSettingsForm();
await loadSlotSettingsForm(stats.users);
await loadCalendarUsers();
await loadDiscordWebhooks();
} catch (err) {

View file

@ -216,9 +216,10 @@ function renderCalendar() {
const rehearsal = rehearsalsByDate.get(isoDate(date));
if (rehearsal) {
cell.classList.add('has-rehearsal');
const isConfirmed = rehearsal.status === 'confirmed';
cell.classList.add('has-rehearsal', isConfirmed ? 'rehearsal-confirmed' : 'rehearsal-suggested');
const badge = document.createElement('span');
badge.title = 'Répétition proposée';
badge.title = isConfirmed ? 'Répétition confirmée' : 'Répétition proposée (en attente de votes)';
badge.textContent = '🎸';
badges.appendChild(badge);
}
@ -488,13 +489,29 @@ function rehearsalVoteActionsHtml(r) {
`;
}
function rehearsalVoterHtml(v, r) {
const isHost = r.hostUserId && v.userId === r.hostUserId;
const name = isHost ? `${v.name}` : v.name;
return `${avatarHtml({ name: v.name, avatarUrl: v.avatarUrl }, 'avatar-sm')}<span>${escapeHtml(name)}</span>`;
}
function rehearsalAcceptedByHtml(r) {
const accepted = r.votes.filter((v) => v.vote === 'accept');
if (!accepted.length) return '';
const refused = r.votes.filter((v) => v.vote === 'reject');
if (!accepted.length && !refused.length) return '';
return `
<div class="rehearsal-accepted-by">
${accepted.map((v) => `${avatarHtml({ name: v.name, avatarUrl: v.avatarUrl }, 'avatar-sm')}<span>${escapeHtml(v.name)}</span>`).join('')}
</div>
${accepted.length ? `
<div class="rehearsal-accepted-by">
<span class="note">Ont accepté :</span>
${accepted.map((v) => rehearsalVoterHtml(v, r)).join('')}
</div>
` : ''}
${refused.length ? `
<div class="rehearsal-accepted-by rehearsal-refused-by">
<span class="note">Ont refusé :</span>
${refused.map((v) => rehearsalVoterHtml(v, r)).join('')}
</div>
` : ''}
`;
}