nodebb-plugin-onekite-calendar 1.0.0

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.
@@ -0,0 +1,215 @@
1
+ <!-- IMPORT admin/partials/settings/header.tpl -->
2
+
3
+ <div class="row">
4
+ <div class="col-lg-9">
5
+ <h1>Calendar OneKite</h1>
6
+
7
+ <ul class="nav nav-tabs mt-3" role="tablist">
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>
10
+ </li>
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>
13
+ </li>
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>
16
+ </li>
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>
19
+ </li>
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>
22
+ </li>
23
+ </ul>
24
+
25
+ <form id="onekite-settings-form">
26
+ <div class="tab-content pt-3">
27
+ <div class="tab-pane fade show active" id="onekite-tab-settings" role="tabpanel">
28
+ <h4>Groupes</h4>
29
+ <div class="mb-3">
30
+ <label class="form-label">Groupes autorisés à créer une demande (csv)</label>
31
+ <input class="form-control" name="creatorGroups" placeholder="ex: registered-users,membres">
32
+ <div class="form-text">Le groupe <code>onekite-ffvl-YYYY</code> est automatiquement ajouté au début. Tu peux ajouter d'autres groupes à la suite.</div>
33
+ </div>
34
+
35
+ <div class="mb-3">
36
+ <label class="form-label">Groupes pouvant valider/supprimer (csv)</label>
37
+ <input class="form-control" name="validatorGroups" placeholder="ex: administrators,location-managers">
38
+ </div>
39
+
40
+ <div class="mb-3">
41
+ <label class="form-label">Groupes notifiés par email (csv)</label>
42
+ <input class="form-control" name="notifyGroups" placeholder="ex: administrators">
43
+ </div>
44
+
45
+ <div class="mb-3">
46
+ <label class="form-label">Durée de blocage en attente (minutes)</label>
47
+ <input class="form-control" name="pendingHoldMinutes" placeholder="5">
48
+ </div>
49
+
50
+ <div class="mb-3">
51
+ <label class="form-label">Délai rappel paiement (minutes)</label>
52
+ <input class="form-control" name="paymentHoldMinutes" placeholder="60">
53
+ <div class="form-text">Après validation (statut <code>paiement en attente</code>), un rappel est envoyé après ce délai. La réservation est ensuite expirée après <strong>2×</strong> ce délai.</div>
54
+ </div>
55
+
56
+ <hr class="my-4" />
57
+ <h4>Discord</h4>
58
+
59
+ <div class="mb-3">
60
+ <label class="form-label">Webhook URL</label>
61
+ <input class="form-control" name="discordWebhookUrl" placeholder="https://discord.com/api/webhooks/...">
62
+ <div class="form-text">Si vide, aucune notification Discord n'est envoyée.</div>
63
+ </div>
64
+
65
+ <div class="mb-3">
66
+ <label class="form-label">Envoyer une notification à la demande</label>
67
+ <select class="form-select" name="discordNotifyOnRequest">
68
+ <option value="1">Oui</option>
69
+ <option value="0">Non</option>
70
+ </select>
71
+ </div>
72
+
73
+ <div class="mb-3">
74
+ <label class="form-label">Envoyer une notification au paiement reçu</label>
75
+ <select class="form-select" name="discordNotifyOnPaid">
76
+ <option value="1">Oui</option>
77
+ <option value="0">Non</option>
78
+ </select>
79
+ </div>
80
+
81
+ <h4 class="mt-4">HelloAsso</h4>
82
+
83
+ <div class="mb-3">
84
+ <label class="form-label">Environnement</label>
85
+ <select class="form-select" name="helloassoEnv">
86
+ <option value="prod">Production</option>
87
+ <option value="sandbox">Sandbox</option>
88
+ </select>
89
+ </div>
90
+
91
+ <div class="mb-3">
92
+ <label class="form-label">Client ID</label>
93
+ <input class="form-control" name="helloassoClientId">
94
+ </div>
95
+
96
+ <div class="mb-3">
97
+ <label class="form-label">Client Secret</label>
98
+ <input class="form-control" name="helloassoClientSecret" type="password">
99
+ </div>
100
+
101
+ <div class="mb-3">
102
+ <label class="form-label">IPs autorisées pour le webhook HelloAsso (csv)</label>
103
+ <input class="form-control" name="helloassoWebhookAllowedIps" placeholder="51.138.206.200,4.233.135.234">
104
+ <div class="form-text">Liste des IPs autorisées à appeler le webhook. Laisse vide pour utiliser la liste par défaut.</div>
105
+ </div>
106
+
107
+ <div class="mb-3">
108
+ <label class="form-label">Organization Slug</label>
109
+ <input class="form-control" name="helloassoOrganizationSlug">
110
+ </div>
111
+
112
+ <div class="mb-3">
113
+ <label class="form-label">Form Type</label>
114
+ <input class="form-control" name="helloassoFormType" placeholder="shop">
115
+ </div>
116
+
117
+ <div class="mb-3">
118
+ <label class="form-label">Form Slug</label>
119
+ <input class="form-control" name="helloassoFormSlug">
120
+ </div>
121
+ <hr class="my-4" />
122
+ <h4>Purge des locations</h4>
123
+ <div class="d-flex gap-2 align-items-center">
124
+ <input class="form-control" style="max-width: 160px;" id="onekite-purge-year" placeholder="YYYY">
125
+ <button type="button" class="btn btn-outline-danger" id="onekite-purge">Purger</button>
126
+ </div>
127
+ <div class="form-text mt-2">Supprime définitivement toutes les locations (réservations) dont la date de début est dans l'année sélectionnée.</div>
128
+ </div>
129
+
130
+ <div class="tab-pane fade" id="onekite-tab-events" role="tabpanel">
131
+ <h4>Évènements (autre couleur)</h4>
132
+ <div class="form-text mb-3">Permet de créer des évènements horaires (début/fin) avec adresse (Leaflet) et notes.</div>
133
+
134
+ <div class="mb-3">
135
+ <label class="form-label">Groupes autorisés à créer des évènements (csv)</label>
136
+ <input class="form-control" name="specialCreatorGroups" placeholder="ex: staff,instructors">
137
+ </div>
138
+
139
+ <div class="mb-3">
140
+ <label class="form-label">Groupes autorisés à supprimer des évènements (csv)</label>
141
+ <input class="form-control" name="specialDeleterGroups" placeholder="Si vide: même liste que la création">
142
+ </div>
143
+
144
+ <hr class="my-4" />
145
+ <h4>Purge des évènements</h4>
146
+ <div class="d-flex gap-2 align-items-center">
147
+ <input class="form-control" style="max-width: 160px;" id="onekite-se-purge-year" placeholder="YYYY">
148
+ <button type="button" class="btn btn-outline-danger" id="onekite-se-purge">Purger</button>
149
+ </div>
150
+ <div class="form-text mt-2">Supprime définitivement tous les évènements dont la date de début est dans l'année sélectionnée.</div>
151
+ </div>
152
+
153
+ <div class="tab-pane fade" id="onekite-tab-pending" role="tabpanel">
154
+ <h4>Demandes en attente</h4>
155
+ <div id="onekite-pending" class="list-group"></div>
156
+ </div>
157
+
158
+ <div class="tab-pane fade" id="onekite-tab-debug" role="tabpanel">
159
+ <p class="text-muted">Teste la récupération du token et la liste du matériel (catalogue).</p>
160
+ <button type="button" class="btn btn-secondary me-2" id="onekite-debug-run">Tester le chargement du matériel</button>
161
+ <pre id="onekite-debug-output" class="mt-3 p-3 border rounded onekite-debug-output" style="max-height: 360px; overflow: auto;"></pre>
162
+ </div>
163
+
164
+ <div class="tab-pane fade" id="onekite-tab-accounting" role="tabpanel">
165
+ <h4>Comptabilisation des locations (payées)</h4>
166
+ <div class="d-flex flex-wrap gap-2 align-items-end mb-3">
167
+ <div>
168
+ <label class="form-label">Du</label>
169
+ <input class="form-control" type="date" id="onekite-acc-from" />
170
+ </div>
171
+ <div>
172
+ <label class="form-label">Au</label>
173
+ <input class="form-control" type="date" id="onekite-acc-to" />
174
+ </div>
175
+ <div>
176
+ <button type="button" class="btn btn-primary" id="onekite-acc-refresh">Rafraîchir</button>
177
+ <button type="button" class="btn btn-outline-secondary" id="onekite-acc-export">Exporter CSV</button>
178
+ <button type="button" class="btn btn-outline-danger" id="onekite-acc-purge">Purger la compta</button>
179
+ </div>
180
+ </div>
181
+
182
+ <h5>Résumé par matériel</h5>
183
+ <div class="table-responsive">
184
+ <table class="table table-sm" id="onekite-acc-summary">
185
+ <thead>
186
+ <tr><th>Matériel</th><th>Nb locations</th><th>Total (€)</th></tr>
187
+ </thead>
188
+ <tbody></tbody>
189
+ </table>
190
+ </div>
191
+
192
+ <h5 class="mt-4">Détails</h5>
193
+ <div class="table-responsive">
194
+ <table class="table table-sm" id="onekite-acc-rows">
195
+ <thead>
196
+ <tr><th>Date</th><th>Utilisateur</th><th>Matériel</th><th>Total (€)</th><th>RID</th></tr>
197
+ </thead>
198
+ <tbody></tbody>
199
+ </table>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </form>
204
+ </div>
205
+ </div>
206
+
207
+ <script>
208
+ require(['admin/plugins/calendar-onekite'], function (mod) {
209
+ if (mod && mod.init) {
210
+ mod.init();
211
+ }
212
+ });
213
+ </script>
214
+
215
+ <!-- IMPORT admin/partials/settings/footer.tpl -->
@@ -0,0 +1,51 @@
1
+ <div class="container">
2
+ <div class="row">
3
+ <div class="col-12">
4
+ <h1>Calendrier</h1>
5
+ <div id="onekite-calendar" style="margin-top: 1rem;"></div>
6
+ </div>
7
+ </div>
8
+ </div>
9
+
10
+ <!--
11
+ FullCalendar
12
+ - Use CDN "latest" so NodeBB v4 stays simple to maintain.
13
+ - Use main.min.css (the global bundle does not ship index.global.min.css).
14
+ -->
15
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fullcalendar@latest/main.min.css" />
16
+ <script src="https://cdn.jsdelivr.net/npm/fullcalendar@latest/index.global.min.js"></script>
17
+ <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/core@latest/locales-all.global.min.js"></script>
18
+
19
+ <!--
20
+ No inline require() here.
21
+ The plugin's forum script auto-initialises on the calendar page via ajaxify.
22
+ -->
23
+
24
+
25
+ <style>
26
+ /* Make the custom "Évènement" button distinct from view buttons */
27
+ .fc .fc-newSpecial-button {
28
+ background: #8e44ad;
29
+ border-color: #8e44ad;
30
+ color: #fff;
31
+ }
32
+ .fc .fc-newSpecial-button:hover {
33
+ filter: brightness(0.95);
34
+ }
35
+
36
+ /* Mobile tweaks for FullCalendar */
37
+ @media (max-width: 576px) {
38
+ #onekite-calendar { margin-top: .5rem !important; }
39
+ .fc .fc-toolbar { flex-wrap: wrap; gap: .25rem; }
40
+ .fc .fc-toolbar-title { font-size: 1.05rem; line-height: 1.2; }
41
+ .fc .fc-button { padding: .25rem .45rem; font-size: .75rem; }
42
+ .fc .fc-button .fc-icon { font-size: .9em; }
43
+ .fc .fc-daygrid-day-number { font-size: .75rem; padding: 2px; }
44
+ .fc .fc-col-header-cell-cushion { font-size: .75rem; padding: 4px 0; }
45
+ .fc .fc-event-title { font-size: .72rem; }
46
+ /* Avoid horizontal scroll */
47
+ .fc { overflow-x: hidden; }
48
+ .fc .fc-scrollgrid, .fc .fc-scrollgrid table { width: 100% !important; }
49
+ }
50
+ </style>
51
+
@@ -0,0 +1,40 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Votre réservation a été validée.</p>
3
+
4
+ <!-- IF validatedBy -->
5
+ <p><strong>Validée par :</strong> <a href="{validatedByUrl}">{validatedBy}</a></p>
6
+ <!-- ENDIF validatedBy -->
7
+
8
+ <p><strong>Matériel</strong></p>
9
+ <ul>
10
+ <!-- BEGIN itemNames -->
11
+ <li>{itemNames}</li>
12
+ <!-- END itemNames -->
13
+ </ul>
14
+
15
+ <p>{dateRange}</p>
16
+
17
+ <!-- IF pickupTime -->
18
+ <p><strong>Heure de récupération :</strong> {pickupTime}</p>
19
+ <!-- ENDIF pickupTime -->
20
+
21
+ <!-- IF pickupAddress -->
22
+ <p><strong>Adresse de récupération :</strong><br>{pickupAddress}</p>
23
+ <!-- ENDIF pickupAddress -->
24
+
25
+ <!-- IF mapUrl -->
26
+ <p style="font-size: 12px; color: #666;">Voir sur la carte : <a href="{mapUrl}">OpenStreetMap</a></p>
27
+ <!-- ENDIF mapUrl -->
28
+
29
+ <!-- IF notes -->
30
+ <p><strong>Notes :</strong><br>{notes}</p>
31
+ <!-- ENDIF notes -->
32
+
33
+ <!-- IF paymentUrl -->
34
+ <p>
35
+ <a href="{paymentUrl}" style="display:inline-block;padding:12px 18px;border-radius:6px;text-decoration:none;border:1px solid #333;">
36
+ Payer maintenant
37
+ </a>
38
+ </p>
39
+ <p style="font-size: 12px; color: #666;">Si le bouton ne fonctionne pas, utilisez ce lien : <a href="{paymentUrl}">{paymentUrl}</a></p>
40
+ <!-- ENDIF paymentUrl -->
@@ -0,0 +1,11 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Votre demande de location de matériel a expiré (paiement non reçu à temps).</p>
3
+
4
+ <p><strong>Matériel</strong></p>
5
+ <ul>
6
+ <!-- BEGIN itemNames -->
7
+ <li>{itemNames}</li>
8
+ <!-- END itemNames -->
9
+ </ul>
10
+
11
+ <p>{dateRange}</p>
@@ -0,0 +1,15 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Nous avons bien reçu votre paiement.</p>
3
+
4
+ <p><strong>Matériel</strong></p>
5
+ <ul>
6
+ <!-- BEGIN itemNames -->
7
+ <li>{itemNames}</li>
8
+ <!-- END itemNames -->
9
+ </ul>
10
+
11
+ <p>{dateRange}</p>
12
+
13
+ <!-- IF paymentReceiptUrl -->
14
+ <p><strong>Reçu :</strong> <a href="{paymentReceiptUrl}">{paymentReceiptUrl}</a></p>
15
+ <!-- ENDIF paymentReceiptUrl -->
@@ -0,0 +1,15 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Nouvelle demande de location de matériel.</p>
3
+
4
+ <p><strong>Demandeur :</strong> {requester}</p>
5
+
6
+ <p><strong>Matériel</strong></p>
7
+ <ul>
8
+ <!-- BEGIN itemNames -->
9
+ <li>{itemNames}</li>
10
+ <!-- END itemNames -->
11
+ </ul>
12
+
13
+ <p>{dateRange}</p>
14
+
15
+ <p><strong>Total estimé :</strong> {total} €</p>
@@ -0,0 +1,15 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Votre demande de location de matériel a été refusée.</p>
3
+
4
+ <p><strong>Matériel réservé</strong></p>
5
+ <ul>
6
+ <!-- BEGIN itemNames -->
7
+ <li>{itemNames}</li>
8
+ <!-- END itemNames -->
9
+ </ul>
10
+
11
+ <p>{dateRange}</p>
12
+
13
+ <!-- IF refusedReason -->
14
+ <p><strong>Raison du refus</strong><br>{refusedReason}</p>
15
+ <!-- ENDIF refusedReason -->
@@ -0,0 +1,20 @@
1
+ <p>Bonjour {username},</p>
2
+ <p>Rappel concernant votre location de matériel.</p>
3
+
4
+ <p><strong>Matériel</strong></p>
5
+ <ul>
6
+ <!-- BEGIN itemNames -->
7
+ <li>{itemNames}</li>
8
+ <!-- END itemNames -->
9
+ </ul>
10
+
11
+ <p>{dateRange}</p>
12
+
13
+ <!-- IF paymentUrl -->
14
+ <p>
15
+ <a href="{paymentUrl}" style="display:inline-block;padding:12px 18px;border-radius:6px;text-decoration:none;border:1px solid #333;">
16
+ Payer maintenant
17
+ </a>
18
+ </p>
19
+ <p style="font-size: 12px; color: #666;">Si le bouton ne fonctionne pas, utilisez ce lien : <a href="{paymentUrl}">{paymentUrl}</a></p>
20
+ <!-- ENDIF paymentUrl -->