nodebb-plugin-onekite-calendar 2.0.19 → 2.0.20

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog – calendar-onekite
2
2
 
3
+ ## 1.3.13
4
+ - Réservations : il est désormais possible de réserver pour le jour même (seules les dates passées sont refusées).
5
+ - Annulation : les validateurs peuvent annuler une réservation déjà payée.
6
+
3
7
  ## 1.3.12
4
8
  - Expiration automatique : envoi d’un email au demandeur avec la raison :
5
9
  - « Demande non prise en charge dans le temps imparti » (demande en attente)
package/lib/api.js CHANGED
@@ -866,16 +866,16 @@ api.createReservation = async function (req, res) {
866
866
  // A validator is "free" only if the rental duration is within the configured threshold.
867
867
  const isValidatorFree = !!isValidator && (validatorFreeMaxDays <= 0 || nbDays <= validatorFreeMaxDays);
868
868
 
869
- // Business rule: a reservation cannot start on the current day or in the past.
869
+ // Business rule: a reservation cannot start in the past.
870
870
  // We compare against server-local midnight. (Front-end also prevents it.)
871
871
  try {
872
872
  const today0 = new Date();
873
873
  today0.setHours(0, 0, 0, 0);
874
- const tomorrow0 = today0.getTime() + 24 * 60 * 60 * 1000;
875
- if (start < tomorrow0) {
874
+ const today0ts = today0.getTime();
875
+ if (start < today0ts) {
876
876
  return res.status(400).json({
877
877
  error: 'date-too-soon',
878
- message: "Impossible de réserver pour aujourd’hui ou une date passée.",
878
+ message: "Impossible de réserver pour une date passée.",
879
879
  });
880
880
  }
881
881
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "2.0.19",
3
+ "version": "2.0.20",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
@@ -866,16 +866,16 @@ api.createReservation = async function (req, res) {
866
866
  // A validator is "free" only if the rental duration is within the configured threshold.
867
867
  const isValidatorFree = !!isValidator && (validatorFreeMaxDays <= 0 || nbDays <= validatorFreeMaxDays);
868
868
 
869
- // Business rule: a reservation cannot start on the current day or in the past.
869
+ // Business rule: a reservation cannot start in the past.
870
870
  // We compare against server-local midnight. (Front-end also prevents it.)
871
871
  try {
872
872
  const today0 = new Date();
873
873
  today0.setHours(0, 0, 0, 0);
874
- const tomorrow0 = today0.getTime() + 24 * 60 * 60 * 1000;
875
- if (start < tomorrow0) {
874
+ const today0ts = today0.getTime();
875
+ if (start < today0ts) {
876
876
  return res.status(400).json({
877
877
  error: 'date-too-soon',
878
- message: "Impossible de réserver pour aujourd’hui ou une date passée.",
878
+ message: "Impossible de réserver pour une date passée.",
879
879
  });
880
880
  }
881
881
  } catch (e) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-calendar",
3
- "version": "1.3.12",
3
+ "version": "1.3.13",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
@@ -39,5 +39,5 @@
39
39
  "acpScripts": [
40
40
  "public/admin.js"
41
41
  ],
42
- "version": "1.3.11"
42
+ "version": "1.3.13"
43
43
  }
@@ -1346,14 +1346,14 @@ function toDatetimeLocalValue(date) {
1346
1346
  return;
1347
1347
  }
1348
1348
 
1349
- // Business rule: reservations cannot start today or in the past.
1349
+ // Business rule: reservations cannot start in the past.
1350
1350
  // (We validate again on the server, but this gives immediate feedback.)
1351
1351
  try {
1352
1352
  const startDateCheck = toLocalYmd(info.start);
1353
1353
  const todayCheck = toLocalYmd(new Date());
1354
- if (startDateCheck <= todayCheck) {
1354
+ if (startDateCheck < todayCheck) {
1355
1355
  lastDateRuleToastAt = Date.now();
1356
- showAlert('error', "Impossible de réserver pour aujourd’hui ou une date passée.");
1356
+ showAlert('error', "Impossible de réserver pour une date passée.");
1357
1357
  calendar.unselect();
1358
1358
  isDialogOpen = false;
1359
1359
  return;
@@ -1413,7 +1413,7 @@ function toDatetimeLocalValue(date) {
1413
1413
  } else if (code === '400' && payload && (payload.error === 'date-too-soon' || payload.code === 'date-too-soon')) {
1414
1414
  // If we already showed the client-side toast a moment ago, avoid a duplicate.
1415
1415
  if (!lastDateRuleToastAt || (Date.now() - lastDateRuleToastAt) > 1500) {
1416
- showAlert('error', String(payload.message || "Impossible de réserver pour aujourd’hui ou une date passée."));
1416
+ showAlert('error', String(payload.message || "Impossible de réserver pour une date passée."));
1417
1417
  }
1418
1418
  } else {
1419
1419
  const msgRaw = payload && (payload.message || payload.error || payload.msg)
@@ -1699,7 +1699,13 @@ function toDatetimeLocalValue(date) {
1699
1699
  const ownerUid = String(ev.extendedProps && ev.extendedProps.uid ? ev.extendedProps.uid : '');
1700
1700
  const isOwner = uidNow && ownerUid && uidNow === ownerUid;
1701
1701
  const showModeration = canModerate && isPending;
1702
- const showCancel = isOwner && ['pending', 'awaiting_payment'].includes(status);
1702
+ // Cancellation rules:
1703
+ // - Owner: can cancel only before payment is completed.
1704
+ // - Validators/admins (canModerate): can cancel even when already paid.
1705
+ const showCancel = (
1706
+ (isOwner && ['pending', 'awaiting_payment'].includes(status)) ||
1707
+ (canModerate && ['pending', 'awaiting_payment', 'approved', 'paid'].includes(status))
1708
+ );
1703
1709
  const paymentUrl = String((p && p.paymentUrl) || '');
1704
1710
  const showPay = isOwner && status === 'awaiting_payment' && /^https?:\/\//i.test(paymentUrl);
1705
1711
  const buttons = {
package/plugin.json CHANGED
@@ -39,5 +39,5 @@
39
39
  "acpScripts": [
40
40
  "public/admin.js"
41
41
  ],
42
- "version": "2.0.19"
42
+ "version": "2.0.20"
43
43
  }
package/public/client.js CHANGED
@@ -1356,14 +1356,14 @@ function toDatetimeLocalValue(date) {
1356
1356
  return;
1357
1357
  }
1358
1358
 
1359
- // Business rule: reservations cannot start today or in the past.
1359
+ // Business rule: reservations cannot start in the past.
1360
1360
  // (We validate again on the server, but this gives immediate feedback.)
1361
1361
  try {
1362
1362
  const startDateCheck = toLocalYmd(info.start);
1363
1363
  const todayCheck = toLocalYmd(new Date());
1364
- if (startDateCheck <= todayCheck) {
1364
+ if (startDateCheck < todayCheck) {
1365
1365
  lastDateRuleToastAt = Date.now();
1366
- showAlert('error', "Impossible de réserver pour aujourd’hui ou une date passée.");
1366
+ showAlert('error', "Impossible de réserver pour une date passée.");
1367
1367
  calendar.unselect();
1368
1368
  isDialogOpen = false;
1369
1369
  return;
@@ -1423,7 +1423,7 @@ function toDatetimeLocalValue(date) {
1423
1423
  } else if (code === '400' && payload && (payload.error === 'date-too-soon' || payload.code === 'date-too-soon')) {
1424
1424
  // If we already showed the client-side toast a moment ago, avoid a duplicate.
1425
1425
  if (!lastDateRuleToastAt || (Date.now() - lastDateRuleToastAt) > 1500) {
1426
- showAlert('error', String(payload.message || "Impossible de réserver pour aujourd’hui ou une date passée."));
1426
+ showAlert('error', String(payload.message || "Impossible de réserver pour une date passée."));
1427
1427
  }
1428
1428
  } else {
1429
1429
  const msgRaw = payload && (payload.message || payload.error || payload.msg)
@@ -1709,7 +1709,13 @@ function toDatetimeLocalValue(date) {
1709
1709
  const ownerUid = String(ev.extendedProps && ev.extendedProps.uid ? ev.extendedProps.uid : '');
1710
1710
  const isOwner = uidNow && ownerUid && uidNow === ownerUid;
1711
1711
  const showModeration = canModerate && isPending;
1712
- const showCancel = isOwner && ['pending', 'awaiting_payment'].includes(status);
1712
+ // Cancellation rules:
1713
+ // - Owner: can cancel only before payment is completed.
1714
+ // - Validators/admins (canModerate): can cancel even when already paid.
1715
+ const showCancel = (
1716
+ (isOwner && ['pending', 'awaiting_payment'].includes(status)) ||
1717
+ (canModerate && ['pending', 'awaiting_payment', 'approved', 'paid'].includes(status))
1718
+ );
1713
1719
  const paymentUrl = String((p && p.paymentUrl) || '');
1714
1720
  const showPay = isOwner && status === 'awaiting_payment' && /^https?:\/\//i.test(paymentUrl);
1715
1721
  const buttons = {