nodebb-plugin-calendar-onekite 11.2.8 → 11.2.10

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 CHANGED
@@ -387,7 +387,7 @@ api.getItems = async function (req, res) {
387
387
  clientSecret: settings.helloassoClientSecret,
388
388
  });
389
389
  if (!token) {
390
- console.warn('[calendar-onekite] HelloAsso access token not obtained (approve API)', { rid });
390
+ console.warn('[calendar-onekite] HelloAsso access token not obtained (items API)', { uid: req.uid || 0 });
391
391
  }
392
392
 
393
393
  if (!token) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-calendar-onekite",
3
- "version": "11.2.8",
3
+ "version": "11.2.10",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -16,10 +16,11 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
16
16
  padding-top: .375rem;
17
17
  padding-bottom: .375rem;
18
18
  line-height: 1.25;
19
+ font-size: 0.95rem;
19
20
  width: 100%;
20
21
  max-width: 100%;
21
22
  box-sizing: border-box;
22
- padding-right: 2.25rem; /* leave room for caret */
23
+ padding-right: 1.75rem; /* leave room for caret */
23
24
  min-width: 0;
24
25
  text-overflow: clip;
25
26
  white-space: nowrap;
@@ -64,8 +65,17 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
64
65
  return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
65
66
  }
66
67
 
67
- function buildLocalDatetime(dateStr, timeStr) {
68
- return `${dateStr}T${timeStr}`;
68
+ // Build an ISO datetime *with timezone* from local date/time inputs.
69
+ // This avoids ambiguity when the server runs in UTC and prevents
70
+ // "single-day" events (07:00→23:59 local) from spilling into the next day
71
+ // when rendered back to the browser.
72
+ function buildLocalIso(dateStr, timeStr) {
73
+ try {
74
+ const d = new Date(`${dateStr}T${timeStr}`);
75
+ return d.toISOString();
76
+ } catch (e) {
77
+ return `${dateStr}T${timeStr}`;
78
+ }
69
79
  }
70
80
 
71
81
  function seTimeOptions(selected, include2359) {
@@ -124,22 +134,22 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
124
134
  <div class="row g-2">
125
135
  <div class="col-12 col-md-6">
126
136
  <label class="form-label">Début</label>
127
- <div class="row g-2">
128
- <div class="col-6">
137
+ <div class="row g-2 align-items-end">
138
+ <div class="col-12 col-sm-8">
129
139
  <input type="date" class="form-control" id="onekite-se-start-date" value="${escapeHtml(toDateInputValue(seStart))}" />
130
140
  </div>
131
- <div class="col-6">
141
+ <div class="col-12 col-sm-4">
132
142
  <select class="form-select onekite-time-select" id="onekite-se-start-time">${seTimeOptions(seStartTime, false)}</select>
133
143
  </div>
134
144
  </div>
135
145
  </div>
136
146
  <div class="col-12 col-md-6">
137
147
  <label class="form-label">Fin</label>
138
- <div class="row g-2">
139
- <div class="col-6">
148
+ <div class="row g-2 align-items-end">
149
+ <div class="col-12 col-sm-8">
140
150
  <input type="date" class="form-control" id="onekite-se-end-date" value="${escapeHtml(toDateInputValue(seEnd))}" />
141
151
  </div>
142
- <div class="col-6">
152
+ <div class="col-12 col-sm-4">
143
153
  <select class="form-select onekite-time-select" id="onekite-se-end-time">${seTimeOptions(seEndTime, true)}</select>
144
154
  </div>
145
155
  </div>
@@ -180,8 +190,8 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
180
190
  const st = (document.getElementById('onekite-se-start-time')?.value || '').trim();
181
191
  const ed = (document.getElementById('onekite-se-end-date')?.value || '').trim();
182
192
  const et = (document.getElementById('onekite-se-end-time')?.value || '').trim();
183
- const startVal = (sd && st) ? buildLocalDatetime(sd, st) : '';
184
- const endVal = (ed && et) ? buildLocalDatetime(ed, et) : '';
193
+ const startVal = (sd && st) ? buildLocalIso(sd, st) : '';
194
+ const endVal = (ed && et) ? buildLocalIso(ed, et) : '';
185
195
  const address = (document.getElementById('onekite-se-address')?.value || '').trim();
186
196
  const notes = (document.getElementById('onekite-se-notes')?.value || '').trim();
187
197
  const lat = (document.getElementById('onekite-se-lat')?.value || '').trim();
@@ -778,13 +788,24 @@ function toDatetimeLocalValue(date) {
778
788
  const btn = document.querySelector('#onekite-calendar .fc-newSpecial-button');
779
789
  if (!btn) return;
780
790
  const isSpecial = mode === 'special';
781
- btn.textContent = isSpecial ? 'Évènement ✓' : 'Évènement';
791
+ const label = isSpecial ? 'Évènement ✓' : 'Évènement';
792
+ // FullCalendar wraps text in a span.fc-button-text. Replacing the entire
793
+ // button textContent can confuse its rerendering and lead to duplicated
794
+ // labels ("EvenementEvenement").
795
+ const span = btn.querySelector('.fc-button-text');
796
+ if (span) {
797
+ span.textContent = label;
798
+ } else {
799
+ btn.textContent = label;
800
+ }
782
801
  btn.classList.toggle('onekite-active', isSpecial);
783
802
  } catch (e) {}
784
803
  }
785
804
 
786
805
  function setMode(next) {
787
806
  mode = next;
807
+ // Reset any pending selection/dialog state when switching modes
808
+ try { if (mode === 'reservation') { calendar.unselect(); isDialogOpen = false; } } catch (e) {}
788
809
  if (mode === 'special') {
789
810
  showAlert('info', 'Mode évènement : sélectionnez une date ou une plage');
790
811
  }
@@ -902,6 +923,21 @@ function toDatetimeLocalValue(date) {
902
923
  failureCallback(e);
903
924
  }
904
925
  },
926
+ eventDidMount: function (arg) {
927
+ try {
928
+ const ev = arg && arg.event;
929
+ if (!ev) return;
930
+ if (ev.extendedProps && ev.extendedProps.type === 'special') {
931
+ // Some themes override FC event colors. Force ours for special events.
932
+ const el2 = arg.el;
933
+ if (el2 && el2.style) {
934
+ el2.style.backgroundColor = '#8e44ad';
935
+ el2.style.borderColor = '#8e44ad';
936
+ el2.style.color = '#ffffff';
937
+ }
938
+ }
939
+ } catch (e) {}
940
+ },
905
941
  select: async function (info) {
906
942
  if (isDialogOpen) {
907
943
  return;