nodebb-plugin-onekite-calendar 2.0.63 → 2.0.64

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
@@ -838,11 +838,19 @@ api.joinSpecialEvent = async function (req, res) {
838
838
  ev.participants = JSON.stringify(list);
839
839
  await dbLayer.saveSpecialEvent(ev);
840
840
 
841
+ const names = await usernamesByUids(list);
842
+
841
843
  realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'participants', eid });
844
+ realtime.emitParticipantsUpdated({
845
+ type: 'special',
846
+ id: eid,
847
+ participants: list,
848
+ participantsUsernames: names,
849
+ });
842
850
  return res.json({
843
851
  ok: true,
844
852
  participants: list,
845
- participantsUsernames: await usernamesByUids(list),
853
+ participantsUsernames: names,
846
854
  });
847
855
  };
848
856
 
@@ -865,8 +873,16 @@ api.leaveSpecialEvent = async function (req, res) {
865
873
  ev.participants = JSON.stringify(next);
866
874
  await dbLayer.saveSpecialEvent(ev);
867
875
 
876
+ const names = await usernamesByUids(next);
877
+
868
878
  realtime.emitCalendarUpdated({ kind: 'specialEvent', action: 'participants', eid });
869
- return res.json({ ok: true, participants: next, participantsUsernames: await usernamesByUids(next) });
879
+ realtime.emitParticipantsUpdated({
880
+ type: 'special',
881
+ id: eid,
882
+ participants: next,
883
+ participantsUsernames: names,
884
+ });
885
+ return res.json({ ok: true, participants: next, participantsUsernames: names });
870
886
  };
871
887
 
872
888
  api.getCapabilities = async function (req, res) {
@@ -1032,8 +1048,16 @@ api.joinOuting = async function (req, res) {
1032
1048
  o.participants = JSON.stringify(list);
1033
1049
  await dbLayer.saveOuting(o);
1034
1050
 
1051
+ const names = await usernamesByUids(list);
1052
+
1035
1053
  realtime.emitCalendarUpdated({ kind: 'outing', action: 'participants', oid });
1036
- return res.json({ ok: true, participants: list, participantsUsernames: await usernamesByUids(list) });
1054
+ realtime.emitParticipantsUpdated({
1055
+ type: 'outing',
1056
+ id: oid,
1057
+ participants: list,
1058
+ participantsUsernames: names,
1059
+ });
1060
+ return res.json({ ok: true, participants: list, participantsUsernames: names });
1037
1061
  };
1038
1062
 
1039
1063
  api.leaveOuting = async function (req, res) {
@@ -1056,8 +1080,16 @@ api.leaveOuting = async function (req, res) {
1056
1080
  o.participants = JSON.stringify(next);
1057
1081
  await dbLayer.saveOuting(o);
1058
1082
 
1083
+ const names = await usernamesByUids(next);
1084
+
1059
1085
  realtime.emitCalendarUpdated({ kind: 'outing', action: 'participants', oid });
1060
- return res.json({ ok: true, participants: next, participantsUsernames: await usernamesByUids(next) });
1086
+ realtime.emitParticipantsUpdated({
1087
+ type: 'outing',
1088
+ id: oid,
1089
+ participants: next,
1090
+ participantsUsernames: names,
1091
+ });
1092
+ return res.json({ ok: true, participants: next, participantsUsernames: names });
1061
1093
  };
1062
1094
 
1063
1095
  api.createOuting = async function (req, res) {
package/lib/realtime.js CHANGED
@@ -27,6 +27,16 @@ function emitCalendarUpdated(payload) {
27
27
  } catch (e) {}
28
28
  }
29
29
 
30
+ function emitParticipantsUpdated(payload) {
31
+ try {
32
+ const server = getIO();
33
+ if (!server || !server.sockets || typeof server.sockets.emit !== 'function') return;
34
+
35
+ server.sockets.emit('event:calendar-onekite.participantsUpdated', payload || {});
36
+ } catch (e) {}
37
+ }
38
+
30
39
  module.exports = {
31
40
  emitCalendarUpdated,
41
+ emitParticipantsUpdated,
32
42
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "2.0.63",
3
+ "version": "2.0.64",
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/plugin.json CHANGED
@@ -39,5 +39,5 @@
39
39
  "acpScripts": [
40
40
  "public/admin.js"
41
41
  ],
42
- "version": "2.0.63"
42
+ "version": "2.0.64"
43
43
  }
package/public/client.js CHANGED
@@ -1705,7 +1705,7 @@ function toDatetimeLocalValue(date) {
1705
1705
  const leaveBtn = (canJoinHere && p.isParticipant)
1706
1706
  ? `<button type="button" class="btn btn-sm btn-danger ms-2 onekite-leave-special" data-eid="${eidPlain}" title="Se retirer" aria-label="Se retirer">−</button>`
1707
1707
  : '';
1708
- const participantsHtml = `<div class="mb-2" id="onekite-participants-special"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
1708
+ const participantsHtml = `<div class="mb-2" id="onekite-participants-special" data-eid="${eidPlain}"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
1709
1709
  (participants.length
1710
1710
  ? participants.map((name) => {
1711
1711
  const u = String(name || '').trim();
@@ -1855,7 +1855,7 @@ function toDatetimeLocalValue(date) {
1855
1855
  const leaveBtn = (canJoinHere && p.isParticipant)
1856
1856
  ? `<button type="button" class="btn btn-sm btn-danger ms-2 onekite-leave-outing" data-oid="${oidPlain}" title="Se retirer" aria-label="Se retirer">−</button>`
1857
1857
  : '';
1858
- const participantsHtml = `<div class="mb-2" id="onekite-participants-outing"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
1858
+ const participantsHtml = `<div class="mb-2" id="onekite-participants-outing" data-oid="${oidPlain}"><strong>Participants</strong>${joinBtn}${leaveBtn}<br>` +
1859
1859
  (participants.length
1860
1860
  ? participants.map((name) => {
1861
1861
  const u = String(name || '').trim();
@@ -2846,6 +2846,63 @@ try {
2846
2846
  scheduleRefetch(cal);
2847
2847
  } catch (e) {}
2848
2848
  });
2849
+
2850
+ // Live update of participants list in open modals (special events & outings)
2851
+ socket.on('event:calendar-onekite.participantsUpdated', function (payload) {
2852
+ try {
2853
+ const p = payload || {};
2854
+ const type = String(p.type || '').trim();
2855
+ const id = String(p.id || '').trim();
2856
+ if (!type || !id) return;
2857
+
2858
+ const names = Array.isArray(p.participantsUsernames) ? p.participantsUsernames : [];
2859
+ const uids = Array.isArray(p.participants) ? p.participants.map(String) : [];
2860
+
2861
+ const uidNow = String(
2862
+ (window.config && window.config.uid) ||
2863
+ (typeof app !== 'undefined' && app && app.user && app.user.uid) ||
2864
+ (typeof ajaxify !== 'undefined' && ajaxify && ajaxify.data && ajaxify.data.uid) ||
2865
+ ''
2866
+ );
2867
+ const isParticipant = uidNow && uids.includes(String(uidNow));
2868
+
2869
+ const sel = (type === 'special') ? '#onekite-participants-special' : (type === 'outing') ? '#onekite-participants-outing' : '';
2870
+ if (!sel) return;
2871
+ const candidates = document.querySelectorAll(sel);
2872
+ if (!candidates || !candidates.length) return;
2873
+ let box = null;
2874
+ for (const el of candidates) {
2875
+ if (!el) continue;
2876
+ const matchId = type === 'special' ? String(el.getAttribute('data-eid') || '') : String(el.getAttribute('data-oid') || '');
2877
+ if (matchId === id) { box = el; break; }
2878
+ }
2879
+ if (!box) return;
2880
+
2881
+ const hasControls = !!box.querySelector('.onekite-join-special, .onekite-leave-special, .onekite-join-outing, .onekite-leave-outing');
2882
+ let controlsHtml = '';
2883
+ if (hasControls && uidNow) {
2884
+ if (type === 'special') {
2885
+ controlsHtml = isParticipant
2886
+ ? `<button type="button" class="btn btn-sm btn-danger ms-2 onekite-leave-special" data-eid="${escapeHtml(id)}" title="Se retirer" aria-label="Se retirer">−</button>`
2887
+ : `<button type="button" class="btn btn-sm btn-success ms-2 onekite-join-special" data-eid="${escapeHtml(id)}" title="S'ajouter" aria-label="S'ajouter">+</button>`;
2888
+ } else if (type === 'outing') {
2889
+ controlsHtml = isParticipant
2890
+ ? `<button type="button" class="btn btn-sm btn-danger ms-2 onekite-leave-outing" data-oid="${escapeHtml(id)}" title="Se retirer" aria-label="Se retirer">−</button>`
2891
+ : `<button type="button" class="btn btn-sm btn-success ms-2 onekite-join-outing" data-oid="${escapeHtml(id)}" title="S'ajouter" aria-label="S'ajouter">+</button>`;
2892
+ }
2893
+ }
2894
+
2895
+ const links = names.length
2896
+ ? names.map((name) => {
2897
+ const u = String(name || '').trim();
2898
+ if (!u) return '';
2899
+ return `<a class="onekite-user-link me-2" href="${window.location.origin}/user/${encodeURIComponent(u)}">${escapeHtml(u)}</a>`;
2900
+ }).filter(Boolean).join('')
2901
+ : `<span class="text-muted">Aucun</span>`;
2902
+
2903
+ box.innerHTML = `<strong>Participants</strong>${controlsHtml}<br>${links}`;
2904
+ } catch (e) {}
2905
+ });
2849
2906
  }
2850
2907
  } catch (e) {}
2851
2908