nodebb-plugin-onekite-calendar 2.0.20 → 2.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/lib/admin.js +10 -0
- package/lib/api.js +27 -0
- package/lib/helloassoWebhook.js +4 -15
- package/lib/realtime.js +36 -0
- package/lib/scheduler.js +7 -0
- package/package.json +1 -1
- package/pkg/package/CHANGELOG.md +30 -0
- package/pkg/package/lib/api.js +10 -0
- package/pkg/package/package.json +1 -1
- package/pkg/package/plugin.json +1 -1
- package/pkg/package/public/client.js +3 -3
- package/plugin.json +1 -1
- package/public/client.js +13 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog – calendar-onekite
|
|
2
2
|
|
|
3
|
+
## 1.3.17
|
|
4
|
+
- Temps réel : les **créations** (locations / évènements), **changements de statut** (validation, refus, annulation, paiement reçu) et **expirations** se répercutent automatiquement sur le calendrier pour **tous les utilisateurs connectés**, sans rechargement de page.
|
|
5
|
+
|
|
6
|
+
## 1.3.16
|
|
7
|
+
- Calendrier : le **jour actuel** n’est plus affiché comme indisponible (gris + panneau sens interdit). Seules les **dates passées** restent désactivées visuellement.
|
|
8
|
+
|
|
9
|
+
## 1.3.15
|
|
10
|
+
- Permissions : les **modérateurs globaux / gestionnaires** (groupe NodeBB « Global Moderators », selon le slug) sont désormais considérés comme validateurs pour les actions de modération (dont l’**annulation**).
|
|
11
|
+
|
|
12
|
+
## 1.3.14
|
|
13
|
+
- Mobile FAB : la modale de sélection de dates autorise désormais la réservation **le jour même** (seules les dates passées sont désactivées).
|
|
14
|
+
|
|
3
15
|
## 1.3.13
|
|
4
16
|
- Réservations : il est désormais possible de réserver pour le jour même (seules les dates passées sont refusées).
|
|
5
17
|
- Annulation : les validateurs peuvent annuler une réservation déjà payée.
|
package/lib/admin.js
CHANGED
|
@@ -73,6 +73,7 @@ function normalizeReturnUrl(meta) {
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
const dbLayer = require('./db');
|
|
76
|
+
const realtime = require('./realtime');
|
|
76
77
|
const helloasso = require('./helloasso');
|
|
77
78
|
|
|
78
79
|
const ADMIN_PRIV = 'admin:settings';
|
|
@@ -207,6 +208,12 @@ admin.approveReservation = async function (req, res) {
|
|
|
207
208
|
|
|
208
209
|
await dbLayer.saveReservation(r);
|
|
209
210
|
|
|
211
|
+
// Real-time refresh for all viewers
|
|
212
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'refused', rid: String(rid), status: r.status });
|
|
213
|
+
|
|
214
|
+
// Real-time refresh for all viewers
|
|
215
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'approved', rid: String(rid), status: r.status });
|
|
216
|
+
|
|
210
217
|
// Email requester
|
|
211
218
|
try {
|
|
212
219
|
const requesterUid = parseInt(r.uid, 10);
|
|
@@ -249,6 +256,9 @@ admin.refuseReservation = async function (req, res) {
|
|
|
249
256
|
r.refusedReason = String((req.body && (req.body.reason || req.body.refusedReason || req.body.refuseReason)) || '').trim();
|
|
250
257
|
await dbLayer.saveReservation(r);
|
|
251
258
|
|
|
259
|
+
// Real-time refresh for all viewers
|
|
260
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'refused', rid: String(rid), status: r.status });
|
|
261
|
+
|
|
252
262
|
try {
|
|
253
263
|
const requesterUid = parseInt(r.uid, 10);
|
|
254
264
|
const requester = await user.getUserFields(requesterUid, ['username']);
|
package/lib/api.js
CHANGED
|
@@ -112,6 +112,7 @@ function normalizeAllowedGroups(raw) {
|
|
|
112
112
|
|
|
113
113
|
const helloasso = require('./helloasso');
|
|
114
114
|
const discord = require('./discord');
|
|
115
|
+
const realtime = require('./realtime');
|
|
115
116
|
|
|
116
117
|
// Email helper (NodeBB 4.x): always send by uid.
|
|
117
118
|
// Subject must be provided inside params.subject.
|
|
@@ -317,6 +318,16 @@ async function canValidate(uid, settings) {
|
|
|
317
318
|
try {
|
|
318
319
|
const isAdmin = await groups.isMember(uid, 'administrators');
|
|
319
320
|
if (isAdmin) return true;
|
|
321
|
+
|
|
322
|
+
// NodeBB has a built-in "Global Moderators" group (slug can vary by install/version).
|
|
323
|
+
// Allow them as validators as well.
|
|
324
|
+
const globalModeratorCandidates = ['global-moderators', 'Global Moderators', 'global moderators'];
|
|
325
|
+
for (const g of globalModeratorCandidates) {
|
|
326
|
+
try {
|
|
327
|
+
// eslint-disable-next-line no-await-in-loop
|
|
328
|
+
if (await groups.isMember(uid, g)) return true;
|
|
329
|
+
} catch (e) {}
|
|
330
|
+
}
|
|
320
331
|
} catch (e) {}
|
|
321
332
|
|
|
322
333
|
const allowed = normalizeAllowedGroups(settings.validatorGroups || '');
|
|
@@ -762,6 +773,8 @@ api.createSpecialEvent = async function (req, res) {
|
|
|
762
773
|
createdAt: String(Date.now()),
|
|
763
774
|
};
|
|
764
775
|
await dbLayer.saveSpecialEvent(ev);
|
|
776
|
+
// Real-time refresh for all viewers
|
|
777
|
+
realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'created', eid: ev.eid });
|
|
765
778
|
res.json({ ok: true, eid });
|
|
766
779
|
};
|
|
767
780
|
|
|
@@ -773,6 +786,7 @@ api.deleteSpecialEvent = async function (req, res) {
|
|
|
773
786
|
const eid = String(req.params.eid || '').replace(/^special:/, '').trim();
|
|
774
787
|
if (!eid) return res.status(400).json({ error: 'bad-id' });
|
|
775
788
|
await dbLayer.removeSpecialEvent(eid);
|
|
789
|
+
realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'deleted', eid });
|
|
776
790
|
res.json({ ok: true });
|
|
777
791
|
};
|
|
778
792
|
|
|
@@ -972,6 +986,9 @@ api.createReservation = async function (req, res) {
|
|
|
972
986
|
// Save
|
|
973
987
|
await dbLayer.saveReservation(resv);
|
|
974
988
|
|
|
989
|
+
// Real-time refresh for all viewers
|
|
990
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'created', rid: resv.rid, status: resv.status });
|
|
991
|
+
|
|
975
992
|
// Audit
|
|
976
993
|
await auditLog(isValidatorFree ? 'reservation_self_checked' : 'reservation_requested', uid, {
|
|
977
994
|
targetType: 'reservation',
|
|
@@ -1174,6 +1191,9 @@ api.approveReservation = async function (req, res) {
|
|
|
1174
1191
|
|
|
1175
1192
|
await dbLayer.saveReservation(r);
|
|
1176
1193
|
|
|
1194
|
+
// Real-time refresh for all viewers
|
|
1195
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'approved', rid: String(rid), status: r.status });
|
|
1196
|
+
|
|
1177
1197
|
await auditLog('reservation_approved', uid, {
|
|
1178
1198
|
targetType: 'reservation',
|
|
1179
1199
|
targetId: String(rid),
|
|
@@ -1241,6 +1261,8 @@ api.refuseReservation = async function (req, res) {
|
|
|
1241
1261
|
}
|
|
1242
1262
|
await dbLayer.saveReservation(r);
|
|
1243
1263
|
|
|
1264
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'refused', rid: String(rid), status: r.status });
|
|
1265
|
+
|
|
1244
1266
|
await auditLog('reservation_refused', uid, {
|
|
1245
1267
|
targetType: 'reservation',
|
|
1246
1268
|
targetId: String(rid),
|
|
@@ -1310,6 +1332,8 @@ api.cancelReservation = async function (req, res) {
|
|
|
1310
1332
|
|
|
1311
1333
|
await dbLayer.saveReservation(r);
|
|
1312
1334
|
|
|
1335
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'cancelled', rid: String(rid), status: r.status });
|
|
1336
|
+
|
|
1313
1337
|
await auditLog('reservation_cancelled', uid, {
|
|
1314
1338
|
targetType: 'reservation',
|
|
1315
1339
|
targetId: String(rid),
|
|
@@ -1385,6 +1409,8 @@ api.setMaintenance = async function (req, res) {
|
|
|
1385
1409
|
targetType: 'item',
|
|
1386
1410
|
targetId: itemId,
|
|
1387
1411
|
});
|
|
1412
|
+
// Maintenance impacts availability; ask clients to refetch.
|
|
1413
|
+
realtime.emitCalendarUpdated({ kind: 'maintenance', action: enabled ? 'on' : 'off', itemId });
|
|
1388
1414
|
return res.json({ ok: true, itemId, enabled });
|
|
1389
1415
|
};
|
|
1390
1416
|
|
|
@@ -1427,6 +1453,7 @@ api.setMaintenanceAll = async function (req, res) {
|
|
|
1427
1453
|
targetId: enabled ? 'all_on' : 'all_off',
|
|
1428
1454
|
count: result && typeof result.count === 'number' ? result.count : (enabled ? catalogIds.length : 0),
|
|
1429
1455
|
});
|
|
1456
|
+
realtime.emitCalendarUpdated({ kind: 'maintenance', action: enabled ? 'all_on' : 'all_off' });
|
|
1430
1457
|
return res.json(Object.assign({ ok: true, enabled }, result || {}));
|
|
1431
1458
|
};
|
|
1432
1459
|
|
package/lib/helloassoWebhook.js
CHANGED
|
@@ -5,19 +5,12 @@ const crypto = require('crypto');
|
|
|
5
5
|
const db = require.main.require('./src/database');
|
|
6
6
|
const meta = require.main.require('./src/meta');
|
|
7
7
|
const user = require.main.require('./src/user');
|
|
8
|
-
// Real-time updates
|
|
9
|
-
let io;
|
|
10
|
-
try {
|
|
11
|
-
const socketIO = require.main.require('./src/socket.io');
|
|
12
|
-
io = socketIO.server || socketIO;
|
|
13
|
-
} catch (e) {
|
|
14
|
-
io = null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
8
|
|
|
18
9
|
const dbLayer = require('./db');
|
|
19
10
|
const helloasso = require('./helloasso');
|
|
20
11
|
const discord = require('./discord');
|
|
12
|
+
const realtime = require('./realtime');
|
|
13
|
+
const realtime = require('./realtime');
|
|
21
14
|
|
|
22
15
|
async function auditLog(action, actorUid, payload) {
|
|
23
16
|
try {
|
|
@@ -342,12 +335,8 @@ async function handler(req, res, next) {
|
|
|
342
335
|
paymentId: r.paymentId || '',
|
|
343
336
|
});
|
|
344
337
|
|
|
345
|
-
// Real-time notify: refresh calendars for all viewers
|
|
346
|
-
|
|
347
|
-
if (io && io.sockets && typeof io.sockets.emit === 'function') {
|
|
348
|
-
io.sockets.emit('event:calendar-onekite.reservationUpdated', { rid: r.rid, status: r.status });
|
|
349
|
-
}
|
|
350
|
-
} catch (e) {}
|
|
338
|
+
// Real-time notify: refresh calendars for all viewers
|
|
339
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'paid', rid: String(r.rid), status: r.status });
|
|
351
340
|
|
|
352
341
|
// Notify requester
|
|
353
342
|
const requesterUid = parseInt(r.uid, 10);
|
package/lib/realtime.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Broadcast real-time calendar updates to all connected clients.
|
|
4
|
+
// NodeBB exposes socket.io via ./src/socket.io (either the server itself or an
|
|
5
|
+
// object with a .server property depending on version).
|
|
6
|
+
|
|
7
|
+
let io;
|
|
8
|
+
|
|
9
|
+
function getIO() {
|
|
10
|
+
if (io) return io;
|
|
11
|
+
try {
|
|
12
|
+
const socketIO = require.main.require('./src/socket.io');
|
|
13
|
+
io = socketIO && socketIO.server ? socketIO.server : socketIO;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
io = null;
|
|
16
|
+
}
|
|
17
|
+
return io;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function emitCalendarUpdated(payload) {
|
|
21
|
+
try {
|
|
22
|
+
const server = getIO();
|
|
23
|
+
if (!server || !server.sockets || typeof server.sockets.emit !== 'function') return;
|
|
24
|
+
|
|
25
|
+
// New event name (generic).
|
|
26
|
+
server.sockets.emit('event:calendar-onekite.calendarUpdated', payload || {});
|
|
27
|
+
|
|
28
|
+
// Backwards compatible event name (older clients only listened to this).
|
|
29
|
+
// Keep it emitted for *any* calendar mutation, not just reservation status.
|
|
30
|
+
server.sockets.emit('event:calendar-onekite.reservationUpdated', payload || {});
|
|
31
|
+
} catch (e) {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
emitCalendarUpdated,
|
|
36
|
+
};
|
package/lib/scheduler.js
CHANGED
|
@@ -4,6 +4,7 @@ const meta = require.main.require('./src/meta');
|
|
|
4
4
|
const db = require.main.require('./src/database');
|
|
5
5
|
const dbLayer = require('./db');
|
|
6
6
|
const discord = require('./discord');
|
|
7
|
+
const realtime = require('./realtime');
|
|
7
8
|
const nconf = require.main.require('nconf');
|
|
8
9
|
const groups = require.main.require('./src/groups');
|
|
9
10
|
|
|
@@ -219,6 +220,9 @@ async function expirePending() {
|
|
|
219
220
|
}
|
|
220
221
|
|
|
221
222
|
await dbLayer.removeReservation(rid);
|
|
223
|
+
|
|
224
|
+
// Real-time refresh for all viewers
|
|
225
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'expired', rid: String(rid), status: 'expired' });
|
|
222
226
|
}
|
|
223
227
|
}
|
|
224
228
|
}
|
|
@@ -380,6 +384,9 @@ async function processAwaitingPayment() {
|
|
|
380
384
|
}
|
|
381
385
|
|
|
382
386
|
await dbLayer.removeReservation(rid);
|
|
387
|
+
|
|
388
|
+
// Real-time refresh for all viewers
|
|
389
|
+
realtime.emitCalendarUpdated({ kind: 'reservation', action: 'expired', rid: String(rid), status: 'expired' });
|
|
383
390
|
}
|
|
384
391
|
}
|
|
385
392
|
}
|
package/package.json
CHANGED
package/pkg/package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog – calendar-onekite
|
|
2
2
|
|
|
3
|
+
## 1.3.16
|
|
4
|
+
- Calendrier : le **jour actuel** n’est plus affiché comme indisponible (gris + panneau sens interdit). Seules les **dates passées** restent désactivées visuellement.
|
|
5
|
+
|
|
6
|
+
## 1.3.15
|
|
7
|
+
- Permissions : les **modérateurs globaux / gestionnaires** (groupe NodeBB « Global Moderators », selon le slug) sont désormais considérés comme validateurs pour les actions de modération (dont l’**annulation**).
|
|
8
|
+
|
|
9
|
+
## 1.3.14
|
|
10
|
+
- Mobile FAB : la modale de sélection de dates autorise désormais la réservation **le jour même** (seules les dates passées sont désactivées).
|
|
11
|
+
|
|
12
|
+
## 1.3.13
|
|
13
|
+
- Réservations : il est désormais possible de réserver pour le jour même (seules les dates passées sont refusées).
|
|
14
|
+
- Annulation : les validateurs peuvent annuler une réservation déjà payée.
|
|
15
|
+
|
|
16
|
+
## 1.3.12
|
|
17
|
+
- Expiration automatique : envoi d’un email au demandeur avec la raison :
|
|
18
|
+
- « Demande non prise en charge dans le temps imparti » (demande en attente)
|
|
19
|
+
- « Paiement non reçu dans le temps imparti » (paiement en attente)
|
|
20
|
+
- ACP : ajout de 2 paramètres pour envoyer un rappel email aux validateurs sur les demandes en attente / paiement en attente.
|
|
21
|
+
- Emails validateurs : nouveaux templates (rappel + expiration) avec lien vers l’ACP.
|
|
22
|
+
|
|
23
|
+
## 1.3.11
|
|
24
|
+
- ACP (Demandes en attente) : affichage du pseudo du demandeur avec lien vers sa fiche utilisateur.
|
|
25
|
+
|
|
26
|
+
## 1.3.10
|
|
27
|
+
- Mobile FAB : surlignage de la sélection de dates rendu lisible en light mode (contraste renforcé, start/end en primary).
|
|
28
|
+
|
|
29
|
+
## 1.3.9
|
|
30
|
+
- Mobile FAB : correction de la sélection de plage (tous les jours sélectionnés sont désormais bien inclus dans la surbrillance).
|
|
31
|
+
- Mobile FAB : amélioration du rendu en mode sombre (bordures/fonds adaptés, contraste renforcé).
|
|
32
|
+
|
|
3
33
|
## 1.3.8
|
|
4
34
|
- ACP Comptabilisation : ajout d’un **grand total** (montant total des locations payées sur la période) + compteurs (payées / sorties gratuites).
|
|
5
35
|
|
package/pkg/package/lib/api.js
CHANGED
|
@@ -317,6 +317,16 @@ async function canValidate(uid, settings) {
|
|
|
317
317
|
try {
|
|
318
318
|
const isAdmin = await groups.isMember(uid, 'administrators');
|
|
319
319
|
if (isAdmin) return true;
|
|
320
|
+
|
|
321
|
+
// NodeBB has a built-in "Global Moderators" group (slug can vary by install/version).
|
|
322
|
+
// Allow them as validators as well.
|
|
323
|
+
const globalModeratorCandidates = ['global-moderators', 'Global Moderators', 'global moderators'];
|
|
324
|
+
for (const g of globalModeratorCandidates) {
|
|
325
|
+
try {
|
|
326
|
+
// eslint-disable-next-line no-await-in-loop
|
|
327
|
+
if (await groups.isMember(uid, g)) return true;
|
|
328
|
+
} catch (e) {}
|
|
329
|
+
}
|
|
320
330
|
} catch (e) {}
|
|
321
331
|
|
|
322
332
|
const allowed = normalizeAllowedGroups(settings.validatorGroups || '');
|
package/pkg/package/package.json
CHANGED
package/pkg/package/plugin.json
CHANGED
|
@@ -31,7 +31,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
31
31
|
touch-action: manipulation;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
/* Show days that cannot be selected for new reservations (
|
|
34
|
+
/* Show days that cannot be selected for new reservations (past only) */
|
|
35
35
|
.fc .onekite-day-disabled {
|
|
36
36
|
background: rgba(0, 0, 0, 0.03);
|
|
37
37
|
}
|
|
@@ -1460,14 +1460,14 @@ function toDatetimeLocalValue(date) {
|
|
|
1460
1460
|
longPressDelay: 300,
|
|
1461
1461
|
selectLongPressDelay: 300,
|
|
1462
1462
|
dayCellDidMount: function (arg) {
|
|
1463
|
-
// Visually disable
|
|
1463
|
+
// Visually disable past days for reservation creation rules,
|
|
1464
1464
|
// without breaking event clicks.
|
|
1465
1465
|
try {
|
|
1466
1466
|
const cellDate = arg && arg.date ? new Date(arg.date) : null;
|
|
1467
1467
|
if (!cellDate) return;
|
|
1468
1468
|
const ymd = toLocalYmd(cellDate);
|
|
1469
1469
|
const today = toLocalYmd(new Date());
|
|
1470
|
-
if (ymd
|
|
1470
|
+
if (ymd < today) {
|
|
1471
1471
|
arg.el.classList.add('onekite-day-disabled');
|
|
1472
1472
|
}
|
|
1473
1473
|
} catch (e) {}
|
package/plugin.json
CHANGED
package/public/client.js
CHANGED
|
@@ -31,7 +31,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
31
31
|
touch-action: manipulation;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
/* Show days that cannot be selected for new reservations (
|
|
34
|
+
/* Show days that cannot be selected for new reservations (past only) */
|
|
35
35
|
.fc .onekite-day-disabled {
|
|
36
36
|
background: rgba(0, 0, 0, 0.03);
|
|
37
37
|
}
|
|
@@ -1470,14 +1470,14 @@ function toDatetimeLocalValue(date) {
|
|
|
1470
1470
|
longPressDelay: 300,
|
|
1471
1471
|
selectLongPressDelay: 300,
|
|
1472
1472
|
dayCellDidMount: function (arg) {
|
|
1473
|
-
// Visually disable
|
|
1473
|
+
// Visually disable past days for reservation creation rules,
|
|
1474
1474
|
// without breaking event clicks.
|
|
1475
1475
|
try {
|
|
1476
1476
|
const cellDate = arg && arg.date ? new Date(arg.date) : null;
|
|
1477
1477
|
if (!cellDate) return;
|
|
1478
1478
|
const ymd = toLocalYmd(cellDate);
|
|
1479
1479
|
const today = toLocalYmd(new Date());
|
|
1480
|
-
if (ymd
|
|
1480
|
+
if (ymd < today) {
|
|
1481
1481
|
arg.el.classList.add('onekite-day-disabled');
|
|
1482
1482
|
}
|
|
1483
1483
|
} catch (e) {}
|
|
@@ -2091,11 +2091,10 @@ function toDatetimeLocalValue(date) {
|
|
|
2091
2091
|
async function openFabDatePicker() {
|
|
2092
2092
|
if (!lockAction('fab-date-picker', 700)) return;
|
|
2093
2093
|
|
|
2094
|
-
// Cannot book
|
|
2094
|
+
// Cannot book past dates (mobile FAB). Same-day booking is allowed.
|
|
2095
2095
|
const today = new Date();
|
|
2096
2096
|
today.setHours(0, 0, 0, 0);
|
|
2097
2097
|
const minStart = new Date(today);
|
|
2098
|
-
minStart.setDate(minStart.getDate() + 1);
|
|
2099
2098
|
|
|
2100
2099
|
// Month cursor for the single-calendar range picker
|
|
2101
2100
|
const cursor = new Date(minStart);
|
|
@@ -2120,7 +2119,7 @@ async function openFabDatePicker() {
|
|
|
2120
2119
|
</div>
|
|
2121
2120
|
<div class="onekite-range-grid" id="onekite-range-grid"></div>
|
|
2122
2121
|
<div class="onekite-range-summary" id="onekite-range-summary"></div>
|
|
2123
|
-
<div class="form-text mt-2">Sélectionne une date de début puis une date de fin (incluse). Les dates
|
|
2122
|
+
<div class="form-text mt-2">Sélectionne une date de début puis une date de fin (incluse). Les dates passées sont désactivées.</div>
|
|
2124
2123
|
</div>
|
|
2125
2124
|
`;
|
|
2126
2125
|
|
|
@@ -2370,10 +2369,17 @@ function autoInit(data) {
|
|
|
2370
2369
|
|
|
2371
2370
|
|
|
2372
2371
|
|
|
2373
|
-
// Live refresh when
|
|
2372
|
+
// Live refresh when the calendar changes (reservation status, new reservation,
|
|
2373
|
+
// new special event, maintenance toggles, webhook payment, etc.)
|
|
2374
2374
|
try {
|
|
2375
2375
|
if (!window.__oneKiteSocketBound && typeof socket !== 'undefined' && socket && typeof socket.on === 'function') {
|
|
2376
2376
|
window.__oneKiteSocketBound = true;
|
|
2377
|
+
socket.on('event:calendar-onekite.calendarUpdated', function () {
|
|
2378
|
+
try {
|
|
2379
|
+
const cal = window.oneKiteCalendar;
|
|
2380
|
+
scheduleRefetch(cal);
|
|
2381
|
+
} catch (e) {}
|
|
2382
|
+
});
|
|
2377
2383
|
socket.on('event:calendar-onekite.reservationUpdated', function () {
|
|
2378
2384
|
try {
|
|
2379
2385
|
const cal = window.oneKiteCalendar;
|