nodebb-plugin-calendar-onekite 11.1.73 → 11.1.74
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/lib/api.js +10 -21
- package/library.js +2 -83
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/public/client.js +123 -11
- package/templates/admin/plugins/calendar-onekite.tpl +6 -6
package/lib/api.js
CHANGED
|
@@ -15,15 +15,12 @@ const helloasso = require('./helloasso');
|
|
|
15
15
|
async function sendEmail(template, toEmail, subject, data) {
|
|
16
16
|
if (!toEmail) return;
|
|
17
17
|
const emailer = require.main.require('./src/emailer');
|
|
18
|
+
const dataWithSubject = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
18
19
|
try {
|
|
19
|
-
//
|
|
20
|
+
// NodeBB's Emailer API differs across versions; the most reliable approach is to pass `subject` inside `data`.
|
|
20
21
|
if (typeof emailer.sendToEmail === 'function') {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (emailer.sendToEmail.length === 3) {
|
|
26
|
-
const dataWithSubject = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
22
|
+
// Prefer 3-args (template, email, data) when possible
|
|
23
|
+
if (emailer.sendToEmail.length >= 3) {
|
|
27
24
|
await emailer.sendToEmail(template, toEmail, dataWithSubject);
|
|
28
25
|
return;
|
|
29
26
|
}
|
|
@@ -32,28 +29,20 @@ async function sendEmail(template, toEmail, subject, data) {
|
|
|
32
29
|
return;
|
|
33
30
|
}
|
|
34
31
|
if (typeof emailer.send === 'function') {
|
|
35
|
-
|
|
36
|
-
if (emailer.send.length >= 4) {
|
|
37
|
-
await emailer.send(template, toEmail, subject, data);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Some builds: (template, email, data)
|
|
41
|
-
// In that case, subject is expected inside `data.subject`.
|
|
42
|
-
if (emailer.send.length === 3) {
|
|
43
|
-
const dataWithSubject = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
32
|
+
if (emailer.send.length >= 3) {
|
|
44
33
|
await emailer.send(template, toEmail, dataWithSubject);
|
|
45
34
|
return;
|
|
46
35
|
}
|
|
47
|
-
// Fallback: try 4-args anyway
|
|
48
36
|
await emailer.send(template, toEmail, subject, data);
|
|
49
37
|
return;
|
|
50
38
|
}
|
|
51
39
|
} catch (err) {
|
|
52
40
|
// eslint-disable-next-line no-console
|
|
53
|
-
console.warn('[calendar-onekite] Failed to send email', { template, toEmail, err: String(err && err.message || err) });
|
|
41
|
+
console.warn('[calendar-onekite] Failed to send email', { template, toEmail, err: String((err && err.message) || err) });
|
|
54
42
|
}
|
|
55
43
|
}
|
|
56
44
|
|
|
45
|
+
|
|
57
46
|
function normalizeBaseUrl(meta) {
|
|
58
47
|
// Prefer meta.config.url, fallback to nconf.get('url')
|
|
59
48
|
let base = (meta && meta.config && (meta.config.url || meta.config['url'])) ? (meta.config.url || meta.config['url']) : '';
|
|
@@ -507,7 +496,7 @@ api.createReservation = async function (req, res) {
|
|
|
507
496
|
await sendEmail(
|
|
508
497
|
'calendar-onekite_pending',
|
|
509
498
|
md.email,
|
|
510
|
-
'Location
|
|
499
|
+
'Location - Demande de réservation',
|
|
511
500
|
{
|
|
512
501
|
username: md.username,
|
|
513
502
|
requester: requester.username,
|
|
@@ -605,7 +594,7 @@ api.approveReservation = async function (req, res) {
|
|
|
605
594
|
const mapUrl = (Number.isFinite(latNum) && Number.isFinite(lonNum))
|
|
606
595
|
? `https://www.openstreetmap.org/?mlat=${encodeURIComponent(String(latNum))}&mlon=${encodeURIComponent(String(lonNum))}#map=18/${encodeURIComponent(String(latNum))}/${encodeURIComponent(String(lonNum))}`
|
|
607
596
|
: '';
|
|
608
|
-
await sendEmail('calendar-onekite_approved', requester.email, 'Location
|
|
597
|
+
await sendEmail('calendar-onekite_approved', requester.email, 'Location - Réservation validée', {
|
|
609
598
|
username: requester.username,
|
|
610
599
|
itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
|
|
611
600
|
itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
|
|
@@ -641,7 +630,7 @@ api.refuseReservation = async function (req, res) {
|
|
|
641
630
|
|
|
642
631
|
const requester = await user.getUserFields(r.uid, ['username', 'email']);
|
|
643
632
|
if (requester && requester.email) {
|
|
644
|
-
await sendEmail('calendar-onekite_refused', requester.email, 'Location
|
|
633
|
+
await sendEmail('calendar-onekite_refused', requester.email, 'Location - Demande de réservation', {
|
|
645
634
|
username: requester.username,
|
|
646
635
|
itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
|
|
647
636
|
itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
|
package/library.js
CHANGED
|
@@ -77,12 +77,12 @@ Plugin.renderMiniWidget = async function (hookData, callback) {
|
|
|
77
77
|
// Note: We render client-side to avoid extra server-side queries. The widget fetches
|
|
78
78
|
// events via the existing public API endpoint.
|
|
79
79
|
widget.html = `
|
|
80
|
-
<div class="calendar-onekite-widget" id="${widgetId}">
|
|
80
|
+
<div class="calendar-onekite-widget" id="${widgetId}" data-show-special="${showSpecial ? '1' : '0'}">
|
|
81
81
|
<div class="calendar-onekite-widget__header">
|
|
82
82
|
<strong>${escapeHtml(title)}</strong>
|
|
83
83
|
<a class="calendar-onekite-widget__link" href="/calendar">Ouvrir</a>
|
|
84
84
|
</div>
|
|
85
|
-
<div class="calendar-onekite-widget__month"
|
|
85
|
+
<div class="calendar-onekite-widget__month"></div>
|
|
86
86
|
<div class="calendar-onekite-widget__legend">
|
|
87
87
|
<span class="calendar-onekite-dot calendar-onekite-dot--pending"></span> en attente
|
|
88
88
|
<span class="calendar-onekite-dot calendar-onekite-dot--paid"></span> payée
|
|
@@ -108,87 +108,6 @@ Plugin.renderMiniWidget = async function (hookData, callback) {
|
|
|
108
108
|
.calendar-onekite-badge--special{background:#fd7e14}
|
|
109
109
|
.calendar-onekite-widget__legend{margin-top:8px;font-size:12px;opacity:.8}
|
|
110
110
|
</style>
|
|
111
|
-
<script>
|
|
112
|
-
(function(){
|
|
113
|
-
const widgetEl = document.getElementById(${JSON.stringify(widgetId)});
|
|
114
|
-
if (!widgetEl) return;
|
|
115
|
-
|
|
116
|
-
const monthEl = widgetEl.querySelector('.calendar-onekite-widget__month');
|
|
117
|
-
const showSpecial = monthEl.getAttribute('data-show-special') === '1';
|
|
118
|
-
|
|
119
|
-
const now = new Date();
|
|
120
|
-
const year = now.getFullYear();
|
|
121
|
-
const month = now.getMonth();
|
|
122
|
-
const first = new Date(year, month, 1);
|
|
123
|
-
const last = new Date(year, month + 1, 0);
|
|
124
|
-
const start = new Date(year, month, 1);
|
|
125
|
-
start.setDate(start.getDate() - ((start.getDay() + 6) % 7)); // Monday-start
|
|
126
|
-
const end = new Date(start);
|
|
127
|
-
end.setDate(end.getDate() + 41);
|
|
128
|
-
|
|
129
|
-
function iso(d){ return d.toISOString(); }
|
|
130
|
-
function ymd(d){ return d.toISOString().slice(0,10); }
|
|
131
|
-
|
|
132
|
-
const apiUrl = window.location.origin + '/api/v3/plugins/calendar-onekite/events?from=' + encodeURIComponent(iso(start)) + '&to=' + encodeURIComponent(iso(end));
|
|
133
|
-
|
|
134
|
-
fetch(apiUrl, { credentials: 'same-origin' })
|
|
135
|
-
.then(r => r.ok ? r.json() : Promise.reject(r))
|
|
136
|
-
.then(payload => {
|
|
137
|
-
const events = Array.isArray(payload) ? payload : (payload.events || payload.data || []);
|
|
138
|
-
const dayMap = new Map();
|
|
139
|
-
for (const ev of events) {
|
|
140
|
-
if (!ev || !ev.start) continue;
|
|
141
|
-
const d = new Date(ev.start);
|
|
142
|
-
const key = ymd(d);
|
|
143
|
-
const props = ev.extendedProps || {};
|
|
144
|
-
const isSpecial = props.type === 'special' || ev.type === 'special' || (ev.classNames || []).includes('onekite-special');
|
|
145
|
-
if (isSpecial && !showSpecial) continue;
|
|
146
|
-
const status = props.status || ev.status || '';
|
|
147
|
-
const bucket = dayMap.get(key) || { pending: 0, paid: 0, special: 0 };
|
|
148
|
-
if (isSpecial) bucket.special++;
|
|
149
|
-
else if (status === 'paid') bucket.paid++;
|
|
150
|
-
else bucket.pending++;
|
|
151
|
-
dayMap.set(key, bucket);
|
|
152
|
-
}
|
|
153
|
-
render(dayMap);
|
|
154
|
-
})
|
|
155
|
-
.catch(() => render(new Map()));
|
|
156
|
-
|
|
157
|
-
function render(dayMap){
|
|
158
|
-
const grid = document.createElement('div');
|
|
159
|
-
grid.className = 'calendar-onekite-widget__grid';
|
|
160
|
-
const labels = ['L','M','M','J','V','S','D'];
|
|
161
|
-
for (const l of labels){
|
|
162
|
-
const el = document.createElement('div');
|
|
163
|
-
el.className = 'calendar-onekite-widget__cell calendar-onekite-widget__cell--muted';
|
|
164
|
-
el.textContent = l;
|
|
165
|
-
grid.appendChild(el);
|
|
166
|
-
}
|
|
167
|
-
for (let i=0;i<42;i++){
|
|
168
|
-
const d = new Date(start);
|
|
169
|
-
d.setDate(start.getDate()+i);
|
|
170
|
-
const cell = document.createElement('a');
|
|
171
|
-
cell.href = '/calendar';
|
|
172
|
-
cell.className = 'calendar-onekite-widget__cell';
|
|
173
|
-
if (d.getMonth() !== month) cell.classList.add('calendar-onekite-widget__cell--muted');
|
|
174
|
-
if (ymd(d) === ymd(now)) cell.classList.add('calendar-onekite-widget__cell--today');
|
|
175
|
-
cell.textContent = d.getDate();
|
|
176
|
-
const b = dayMap.get(ymd(d));
|
|
177
|
-
if (b && (b.pending || b.paid || b.special)){
|
|
178
|
-
const badges = document.createElement('div');
|
|
179
|
-
badges.className = 'calendar-onekite-badges';
|
|
180
|
-
if (b.pending) { const s=document.createElement('span'); s.className='calendar-onekite-badge calendar-onekite-badge--pending'; badges.appendChild(s); }
|
|
181
|
-
if (b.paid) { const s=document.createElement('span'); s.className='calendar-onekite-badge calendar-onekite-badge--paid'; badges.appendChild(s); }
|
|
182
|
-
if (showSpecial && b.special) { const s=document.createElement('span'); s.className='calendar-onekite-badge calendar-onekite-badge--special'; badges.appendChild(s); }
|
|
183
|
-
cell.appendChild(badges);
|
|
184
|
-
}
|
|
185
|
-
grid.appendChild(cell);
|
|
186
|
-
}
|
|
187
|
-
monthEl.innerHTML = '';
|
|
188
|
-
monthEl.appendChild(grid);
|
|
189
|
-
}
|
|
190
|
-
})();
|
|
191
|
-
</script>
|
|
192
111
|
`;
|
|
193
112
|
|
|
194
113
|
hookData.widget = widget;
|
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/client.js
CHANGED
|
@@ -18,7 +18,15 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
18
18
|
|
|
19
19
|
async function openSpecialEventDialog(selectionInfo) {
|
|
20
20
|
const start = selectionInfo.start;
|
|
21
|
-
|
|
21
|
+
let end = selectionInfo.end;
|
|
22
|
+
// FullCalendar all-day selection uses an exclusive end (next day 00:00). For a single-day click,
|
|
23
|
+
// this looks like a 2-day range. Default to a 1-hour duration in that case.
|
|
24
|
+
try {
|
|
25
|
+
if (selectionInfo && selectionInfo.allDay && start && end && (end.getTime() - start.getTime()) <= 86400000 + 1000) {
|
|
26
|
+
end = new Date(start.getTime() + 60 * 60 * 1000);
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {}
|
|
29
|
+
|
|
22
30
|
const html = `
|
|
23
31
|
<div class="mb-3">
|
|
24
32
|
<label class="form-label">Titre</label>
|
|
@@ -51,7 +59,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
51
59
|
`;
|
|
52
60
|
|
|
53
61
|
return await new Promise((resolve) => {
|
|
54
|
-
bootbox.dialog({
|
|
62
|
+
const dlg = bootbox.dialog({
|
|
55
63
|
title: 'Créer un évènement',
|
|
56
64
|
message: html,
|
|
57
65
|
buttons: {
|
|
@@ -78,14 +86,18 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
78
86
|
},
|
|
79
87
|
});
|
|
80
88
|
|
|
81
|
-
// init leaflet
|
|
82
|
-
|
|
89
|
+
// init leaflet once the modal is visible (Leaflet needs a laid-out container)
|
|
90
|
+
dlg.on('shown.bs.modal', async () => {
|
|
83
91
|
try {
|
|
84
92
|
const mapEl = document.getElementById('onekite-se-map');
|
|
85
93
|
if (!mapEl) return;
|
|
86
94
|
const L = await loadLeaflet();
|
|
87
95
|
const map = L.map(mapEl).setView([46.5, 2.5], 5);
|
|
88
96
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map);
|
|
97
|
+
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
try { map.invalidateSize(); } catch (e) {}
|
|
100
|
+
}, 50);
|
|
89
101
|
let marker = null;
|
|
90
102
|
function setMarker(lat, lon) {
|
|
91
103
|
if (marker) map.removeLayer(marker);
|
|
@@ -114,7 +126,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
114
126
|
} catch (e) {
|
|
115
127
|
// ignore leaflet errors
|
|
116
128
|
}
|
|
117
|
-
}
|
|
129
|
+
});
|
|
118
130
|
});
|
|
119
131
|
}
|
|
120
132
|
|
|
@@ -125,12 +137,12 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
125
137
|
${safeAddr ? `<div class="mb-2">${escapeHtml(safeAddr)}</div>` : ''}
|
|
126
138
|
<div id="${mapId}" style="height:260px; border:1px solid #ddd; border-radius:6px;"></div>
|
|
127
139
|
`;
|
|
128
|
-
bootbox.dialog({
|
|
140
|
+
const dlg = bootbox.dialog({
|
|
129
141
|
title: title || 'Carte',
|
|
130
142
|
message: html,
|
|
131
143
|
buttons: { close: { label: 'Fermer', className: 'btn-secondary' } },
|
|
132
144
|
});
|
|
133
|
-
|
|
145
|
+
dlg.on('shown.bs.modal', async () => {
|
|
134
146
|
try {
|
|
135
147
|
const el = document.getElementById(mapId);
|
|
136
148
|
if (!el) return;
|
|
@@ -156,10 +168,14 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
156
168
|
}
|
|
157
169
|
}
|
|
158
170
|
map.setView([46.5, 2.5], 5);
|
|
171
|
+
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
try { map.invalidateSize(); } catch (e) {}
|
|
174
|
+
}, 50);
|
|
159
175
|
} catch (e) {
|
|
160
176
|
// ignore leaflet errors
|
|
161
177
|
}
|
|
162
|
-
}
|
|
178
|
+
});
|
|
163
179
|
}
|
|
164
180
|
|
|
165
181
|
// Click handler for map links in popups
|
|
@@ -536,9 +552,10 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
536
552
|
isDialogOpen = false;
|
|
537
553
|
return;
|
|
538
554
|
}
|
|
539
|
-
// Send date strings
|
|
540
|
-
|
|
541
|
-
const
|
|
555
|
+
// Send date-only strings from FullCalendar to avoid timezone shifts.
|
|
556
|
+
// For all-day selections, startStr/endStr are YYYY-MM-DD (end is exclusive).
|
|
557
|
+
const startDate = info.startStr;
|
|
558
|
+
const endDate = info.endStr;
|
|
542
559
|
await requestReservation({
|
|
543
560
|
start: startDate,
|
|
544
561
|
end: endDate,
|
|
@@ -806,6 +823,12 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
806
823
|
// Default view (France-ish)
|
|
807
824
|
map.setView([46.7, 2.5], 5);
|
|
808
825
|
|
|
826
|
+
// Bootbox/Bootstrap modal layouts can report a zero-sized container on first paint.
|
|
827
|
+
// Force Leaflet to recompute sizes once the modal is fully displayed.
|
|
828
|
+
setTimeout(() => {
|
|
829
|
+
try { map.invalidateSize(); } catch (e) {}
|
|
830
|
+
}, 50);
|
|
831
|
+
|
|
809
832
|
let marker = null;
|
|
810
833
|
function setMarker(lat, lon, zoom) {
|
|
811
834
|
const ll = [lat, lon];
|
|
@@ -903,6 +926,95 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
903
926
|
// call once after current tick.
|
|
904
927
|
setTimeout(() => autoInit({ template: (ajaxify && ajaxify.data && ajaxify.data.template) || { name: '' } }), 0);
|
|
905
928
|
|
|
929
|
+
// Render mini widgets (ACP Widgets) without inline scripts (CSP-friendly).
|
|
930
|
+
async function renderMiniWidgets() {
|
|
931
|
+
const widgets = Array.from(document.querySelectorAll('.calendar-onekite-widget'));
|
|
932
|
+
if (!widgets.length) return;
|
|
933
|
+
|
|
934
|
+
const now = new Date();
|
|
935
|
+
const year = now.getFullYear();
|
|
936
|
+
const month = now.getMonth();
|
|
937
|
+
|
|
938
|
+
const start = new Date(year, month, 1);
|
|
939
|
+
start.setDate(start.getDate() - ((start.getDay() + 6) % 7)); // Monday-start
|
|
940
|
+
const end = new Date(start);
|
|
941
|
+
end.setDate(end.getDate() + 41);
|
|
942
|
+
|
|
943
|
+
function iso(d){ return d.toISOString(); }
|
|
944
|
+
function ymd(d){ return d.toISOString().slice(0, 10); }
|
|
945
|
+
|
|
946
|
+
let events = [];
|
|
947
|
+
try {
|
|
948
|
+
const qs = new URLSearchParams({ start: iso(start), end: iso(end) });
|
|
949
|
+
events = await fetchJson(`/api/v3/plugins/calendar-onekite/events?${qs.toString()}`)
|
|
950
|
+
.catch(() => fetchJson(`/api/plugins/calendar-onekite/events?${qs.toString()}`));
|
|
951
|
+
} catch (e) {
|
|
952
|
+
events = [];
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const dayMap = new Map();
|
|
956
|
+
for (const ev of (events || [])) {
|
|
957
|
+
if (!ev || !ev.start) continue;
|
|
958
|
+
const d = new Date(ev.start);
|
|
959
|
+
const key = ymd(d);
|
|
960
|
+
const props = ev.extendedProps || {};
|
|
961
|
+
const isSpecial = props.type === 'special' || ev.type === 'special' || (ev.classNames || []).includes('onekite-special');
|
|
962
|
+
const status = props.status || ev.status || '';
|
|
963
|
+
const bucket = dayMap.get(key) || { pending: 0, paid: 0, special: 0 };
|
|
964
|
+
if (isSpecial) bucket.special++;
|
|
965
|
+
else if (status === 'paid') bucket.paid++;
|
|
966
|
+
else bucket.pending++;
|
|
967
|
+
dayMap.set(key, bucket);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
for (const widgetEl of widgets) {
|
|
971
|
+
const monthEl = widgetEl.querySelector('.calendar-onekite-widget__month');
|
|
972
|
+
if (!monthEl) continue;
|
|
973
|
+
const showSpecial = widgetEl.getAttribute('data-show-special') === '1';
|
|
974
|
+
|
|
975
|
+
const grid = document.createElement('div');
|
|
976
|
+
grid.className = 'calendar-onekite-widget__grid';
|
|
977
|
+
const labels = ['L','M','M','J','V','S','D'];
|
|
978
|
+
for (const l of labels) {
|
|
979
|
+
const el = document.createElement('div');
|
|
980
|
+
el.className = 'calendar-onekite-widget__cell calendar-onekite-widget__cell--muted';
|
|
981
|
+
el.textContent = l;
|
|
982
|
+
grid.appendChild(el);
|
|
983
|
+
}
|
|
984
|
+
for (let i = 0; i < 42; i++) {
|
|
985
|
+
const d = new Date(start);
|
|
986
|
+
d.setDate(start.getDate() + i);
|
|
987
|
+
const cell = document.createElement('a');
|
|
988
|
+
cell.href = '/calendar';
|
|
989
|
+
cell.className = 'calendar-onekite-widget__cell';
|
|
990
|
+
if (d.getMonth() !== month) cell.classList.add('calendar-onekite-widget__cell--muted');
|
|
991
|
+
if (ymd(d) === ymd(now)) cell.classList.add('calendar-onekite-widget__cell--today');
|
|
992
|
+
cell.textContent = d.getDate();
|
|
993
|
+
|
|
994
|
+
const b = dayMap.get(ymd(d));
|
|
995
|
+
if (b && (b.pending || b.paid || (showSpecial && b.special))) {
|
|
996
|
+
const badges = document.createElement('div');
|
|
997
|
+
badges.className = 'calendar-onekite-badges';
|
|
998
|
+
if (b.pending) { const s = document.createElement('span'); s.className = 'calendar-onekite-badge calendar-onekite-badge--pending'; badges.appendChild(s); }
|
|
999
|
+
if (b.paid) { const s = document.createElement('span'); s.className = 'calendar-onekite-badge calendar-onekite-badge--paid'; badges.appendChild(s); }
|
|
1000
|
+
if (showSpecial && b.special) { const s = document.createElement('span'); s.className = 'calendar-onekite-badge calendar-onekite-badge--special'; badges.appendChild(s); }
|
|
1001
|
+
cell.appendChild(badges);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
grid.appendChild(cell);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
monthEl.innerHTML = '';
|
|
1008
|
+
monthEl.appendChild(grid);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Re-render widgets on every page load/end.
|
|
1013
|
+
if (hooks && typeof hooks.on === 'function') {
|
|
1014
|
+
hooks.on('action:ajaxify.end', () => { renderMiniWidgets().catch(() => {}); });
|
|
1015
|
+
}
|
|
1016
|
+
setTimeout(() => { renderMiniWidgets().catch(() => {}); }, 0);
|
|
1017
|
+
|
|
906
1018
|
|
|
907
1019
|
|
|
908
1020
|
// Live refresh when a reservation changes (e.g., payment confirmed by webhook)
|
|
@@ -6,19 +6,19 @@
|
|
|
6
6
|
|
|
7
7
|
<ul class="nav nav-tabs mt-3" role="tablist">
|
|
8
8
|
<li class="nav-item" role="presentation">
|
|
9
|
-
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#onekite-tab-settings" type="button" role="tab">Locations</button>
|
|
9
|
+
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#onekite-tab-settings" type="button" role="tab" aria-controls="onekite-tab-settings" aria-selected="true">Locations</button>
|
|
10
10
|
</li>
|
|
11
11
|
<li class="nav-item" role="presentation">
|
|
12
|
-
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-events" type="button" role="tab">Évènements</button>
|
|
12
|
+
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-events" type="button" role="tab" aria-controls="onekite-tab-events" aria-selected="false">Évènements</button>
|
|
13
13
|
</li>
|
|
14
14
|
<li class="nav-item" role="presentation">
|
|
15
|
-
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-pending" type="button" role="tab">Demandes en attente</button>
|
|
15
|
+
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-pending" type="button" role="tab" aria-controls="onekite-tab-pending" aria-selected="false">Demandes en attente</button>
|
|
16
16
|
</li>
|
|
17
17
|
<li class="nav-item" role="presentation">
|
|
18
|
-
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-debug" type="button" role="tab">Debug HelloAsso</button>
|
|
18
|
+
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-debug" type="button" role="tab" aria-controls="onekite-tab-debug" aria-selected="false">Debug HelloAsso</button>
|
|
19
19
|
</li>
|
|
20
20
|
<li class="nav-item" role="presentation">
|
|
21
|
-
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-accounting" type="button" role="tab">Comptabilisation</button>
|
|
21
|
+
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#onekite-tab-accounting" type="button" role="tab" aria-controls="onekite-tab-accounting" aria-selected="false">Comptabilisation</button>
|
|
22
22
|
</li>
|
|
23
23
|
</ul>
|
|
24
24
|
|
|
@@ -183,4 +183,4 @@
|
|
|
183
183
|
});
|
|
184
184
|
</script>
|
|
185
185
|
|
|
186
|
-
<!-- IMPORT admin/partials/settings/footer.tpl -->
|
|
186
|
+
<!-- IMPORT admin/partials/settings/footer.tpl -->
|