@ourlu/assistant-sdk 0.2.3 → 0.2.5

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.
Files changed (51) hide show
  1. package/dist/iife/audio.v1.028c93fe.js +160 -0
  2. package/dist/iife/audio.v1.051ececf.js +183 -0
  3. package/dist/iife/audio.v1.200db1a6.js +208 -0
  4. package/dist/iife/audio.v1.20858b08.js +191 -0
  5. package/dist/iife/audio.v1.2690e445.js +179 -0
  6. package/dist/iife/audio.v1.2742ff12.js +188 -0
  7. package/dist/iife/audio.v1.70af81b3.js +191 -0
  8. package/dist/iife/audio.v1.95146620.js +1 -1
  9. package/dist/iife/audio.v1.b330baaf.js +166 -0
  10. package/dist/iife/audio.v1.bb9c2d88.js +181 -0
  11. package/dist/iife/audio.v1.ea7571b2.js +182 -0
  12. package/dist/iife/audio.v1.fc0aa8af.js +191 -0
  13. package/dist/iife/audio.v1.js +107 -95
  14. package/dist/iife/engine.v1.2b5bb43b.js +735 -0
  15. package/dist/iife/engine.v1.3b09dc20.js +3 -3
  16. package/dist/iife/engine.v1.56074e5a.js +769 -0
  17. package/dist/iife/engine.v1.61c10e6c.js +770 -0
  18. package/dist/iife/engine.v1.773fc15d.js +2 -2
  19. package/dist/iife/engine.v1.80d2230f.js +770 -0
  20. package/dist/iife/engine.v1.940ba9ea.js +764 -0
  21. package/dist/iife/engine.v1.99a33ee2.js +767 -0
  22. package/dist/iife/engine.v1.9ca6b7ec.js +756 -0
  23. package/dist/iife/engine.v1.a1f7dea2.js +764 -0
  24. package/dist/iife/engine.v1.c0c00bd0.js +721 -0
  25. package/dist/iife/engine.v1.c127656e.js +820 -0
  26. package/dist/iife/engine.v1.c54c9a1a.js +770 -0
  27. package/dist/iife/engine.v1.d1052e81.js +770 -0
  28. package/dist/iife/engine.v1.f6d23a0f.js +770 -0
  29. package/dist/iife/engine.v1.js +135 -36
  30. package/dist/iife/loader.v1.js +5 -1
  31. package/dist/iife/signalement.v1.d321dfde.js +518 -0
  32. package/dist/iife/signalement.v1.js +518 -0
  33. package/dist/iife/ui.v1.00abf020.js +895 -0
  34. package/dist/iife/ui.v1.5d2d4504.js +942 -0
  35. package/dist/iife/ui.v1.6afac75f.js +944 -0
  36. package/dist/iife/ui.v1.6becaa84.js +895 -0
  37. package/dist/iife/ui.v1.6c9e4995.js +895 -0
  38. package/dist/iife/ui.v1.7fb4db0b.js +935 -0
  39. package/dist/iife/ui.v1.88bf5494.js +898 -0
  40. package/dist/iife/ui.v1.923a4e6d.js +937 -0
  41. package/dist/iife/ui.v1.9bfe2815.js +942 -0
  42. package/dist/iife/ui.v1.a8cfe724.js +900 -0
  43. package/dist/iife/ui.v1.c58e1d58.js +959 -0
  44. package/dist/iife/ui.v1.cdfe9a45.js +919 -0
  45. package/dist/iife/ui.v1.e007c7c4.js +926 -0
  46. package/dist/iife/ui.v1.e24ba2bd.js +903 -0
  47. package/dist/iife/ui.v1.f1d8e998.js +903 -0
  48. package/dist/iife/ui.v1.fc52b520.js +895 -0
  49. package/dist/iife/ui.v1.js +154 -147
  50. package/dist/iife/widget-manifest.json +4 -3
  51. package/package.json +2 -1
@@ -0,0 +1,518 @@
1
+ (function() {
2
+ "use strict";
3
+ var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
4
+
5
+ function SignalementCssBuilder() {}
6
+
7
+ SignalementCssBuilder.prototype.build = function() {
8
+ return [
9
+ this.buildTabsBar(),
10
+ this.buildTabContent(),
11
+ this.buildFormSections(),
12
+ this.buildCategories(),
13
+ this.buildPhotos(),
14
+ this.buildLocation(),
15
+ this.buildSignalementButton(),
16
+ this.buildMobileOverrides()
17
+ ].join("\n");
18
+ };
19
+
20
+ SignalementCssBuilder.prototype.buildTabsBar = function() {
21
+ return [
22
+ "#cm-tabs-bar{display:none;gap:0;background:#f8fafc;border-bottom:1px solid #e2e8f0;flex-shrink:0;padding:0 4px}",
23
+ "#cm-tabs-bar.visible{display:flex}",
24
+ ".cm-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;border:none;background:none;color:#94a3b8;font-size:13.5px;font-weight:500;cursor:pointer;position:relative;transition:color .2s;border-bottom:2.5px solid transparent;font-family:inherit}",
25
+ ".cm-tab svg{width:16px;height:16px;flex-shrink:0}",
26
+ ".cm-tab:hover{color:#475569}",
27
+ ".cm-tab.active{color:#0066ff;border-bottom-color:#0066ff;font-weight:600}",
28
+ ".cm-tab-close{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;border:none;background:transparent;color:inherit;cursor:pointer;opacity:.5;transition:all .15s;padding:0;margin-left:4px}",
29
+ ".cm-tab-close svg{width:12px;height:12px}",
30
+ ".cm-tab-close:hover{opacity:1;background:rgba(0,0,0,.08)}",
31
+ ".cm-tab[data-tab='signalement'].hidden{display:none}"
32
+ ].join("\n");
33
+ };
34
+
35
+ SignalementCssBuilder.prototype.buildTabContent = function() {
36
+ return [
37
+ "#cm-signalement-content{display:none;flex-direction:column;flex:1;overflow:hidden}",
38
+ "#cm-signalement-content.active{display:flex}",
39
+ ".cm-signalement-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:16px;display:flex;flex-direction:column;gap:18px;min-width:0;width:100%}",
40
+ ".cm-signalement-scroll::-webkit-scrollbar{width:6px}",
41
+ ".cm-signalement-scroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,.1);border-radius:3px}"
42
+ ].join("\n");
43
+ };
44
+
45
+ SignalementCssBuilder.prototype.buildFormSections = function() {
46
+ return [
47
+ ".cm-sig-section{display:flex;flex-direction:column;min-width:0;padding-bottom:14px;border-bottom:1px solid #e2e8f0}",
48
+ ".cm-sig-label{font-size:12px;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}",
49
+ ".cm-sig-label-opt{font-weight:400;text-transform:none;letter-spacing:0;color:#94a3b8;font-size:11px}"
50
+ ].join("\n");
51
+ };
52
+
53
+ SignalementCssBuilder.prototype.buildCategories = function() {
54
+ return [
55
+ ".cm-sig-cats{display:flex;gap:6px;overflow-x:scroll;overflow-y:hidden;flex-wrap:nowrap;padding-bottom:6px;-webkit-overflow-scrolling:touch;scrollbar-width:none;max-width:100%}",
56
+ ".cm-sig-cats::-webkit-scrollbar{display:none}",
57
+ ".cm-sig-cat{display:flex;align-items:center;gap:5px;padding:10px 18px;border-radius:20px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:14px;font-weight:500;cursor:pointer;transition:all .15s;white-space:nowrap;flex-shrink:0;font-family:inherit}",
58
+ ".cm-sig-cat svg{width:18px;height:18px}",
59
+ ".cm-sig-cat:hover{border-color:#93c5fd;background:#eff6ff;color:#1d4ed8}",
60
+ ".cm-sig-cat.active{border-color:#0066ff;background:#eff6ff;color:#0066ff;font-weight:600;box-shadow:0 0 0 2px rgba(0,102,255,.12)}"
61
+ ].join("\n");
62
+ };
63
+
64
+ SignalementCssBuilder.prototype.buildPhotos = function() {
65
+ return [
66
+ ".cm-sig-photo-actions{display:flex;gap:8px;margin-bottom:5px}",
67
+ ".cm-sig-photo-btn{display:flex;align-items:center;gap:5px;padding:8px 16px;border-radius:10px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:14px;font-weight:500;cursor:pointer;transition:all .15s;font-family:inherit}",
68
+ ".cm-sig-photo-btn svg{width:18px;height:18px}",
69
+ ".cm-sig-photo-btn:hover{border-color:#93c5fd;background:#eff6ff;color:#1d4ed8}",
70
+ ".cm-sig-grid{display:flex;gap:10px;flex-wrap:wrap;margin-top:5px}",
71
+ ".cm-sig-thumb{width:88px;height:88px;border-radius:12px;overflow:hidden;position:relative;border:1.5px solid #e2e8f0;box-shadow:0 2px 6px rgba(0,0,0,.06)}",
72
+ ".cm-sig-thumb img{width:100%;height:100%;object-fit:cover}",
73
+ ".cm-sig-thumb-rm{position:absolute;top:4px;right:4px;width:24px;height:24px;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;border:none;cursor:pointer;font-size:15px;display:flex;align-items:center;justify-content:center;line-height:1;transition:background .15s}",
74
+ ".cm-sig-thumb-rm:hover{background:rgba(220,38,38,.9)}",
75
+ ".cm-sig-add{width:88px;height:88px;border-radius:12px;border:2px dashed #cbd5e1;background:#f8fafc;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:border-color .2s,background .2s;color:#94a3b8}",
76
+ ".cm-sig-add svg{width:28px;height:28px}",
77
+ ".cm-sig-add:hover{border-color:#0066ff;background:#eff6ff;color:#0066ff}"
78
+ ].join("\n");
79
+ };
80
+
81
+ SignalementCssBuilder.prototype.buildLocation = function() {
82
+ return [
83
+ ".cm-sig-loc-row{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:12px;background:#f0fdf4;border:1.5px solid #bbf7d0;transition:background .25s,border-color .25s}",
84
+ ".cm-sig-loc-row.denied{background:#fef2f2;border-color:#fecaca}",
85
+ ".cm-sig-loc-status{display:flex;align-items:center;gap:10px}",
86
+ ".cm-sig-loc-globe{position:relative;flex-shrink:0;width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:#dcfce7;border-radius:50%;transition:background .25s}",
87
+ ".cm-sig-loc-row.denied .cm-sig-loc-globe{background:#fee2e2}",
88
+ ".cm-sig-loc-check{position:absolute;top:-2px;right:-2px;width:16px;height:16px;border-radius:50%;background:#16a34a;color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;line-height:1;transition:background .25s}",
89
+ ".cm-sig-loc-row.denied .cm-sig-loc-check{background:#dc2626}",
90
+ ".cm-sig-loc-info{display:flex;flex-direction:column;gap:1px}",
91
+ ".cm-sig-loc-text{font-size:13px;font-weight:600;color:#15803d;transition:color .25s}",
92
+ ".cm-sig-loc-row.denied .cm-sig-loc-text{color:#dc2626}",
93
+ ".cm-sig-loc-addr{font-size:12px;color:#4ade80;font-weight:400;transition:color .25s}",
94
+ ".cm-sig-loc-row.denied .cm-sig-loc-addr{color:#fca5a5}",
95
+ ".cm-sig-toggle{position:relative;display:inline-block;width:52px;height:28px;flex-shrink:0;cursor:pointer}",
96
+ ".cm-sig-toggle input{opacity:0;width:0;height:0}",
97
+ ".cm-sig-toggle-slider{position:absolute;inset:0;background:#cbd5e1;border-radius:28px;transition:background .25s}",
98
+ ".cm-sig-toggle-slider::before{content:'';position:absolute;width:22px;height:22px;border-radius:50%;left:3px;bottom:3px;background:#fff;transition:transform .25s;box-shadow:0 1px 3px rgba(0,0,0,.15)}",
99
+ ".cm-sig-toggle input:checked+.cm-sig-toggle-slider{background:#16a34a}",
100
+ ".cm-sig-toggle input:checked+.cm-sig-toggle-slider::before{transform:translateX(24px)}"
101
+ ].join("\n");
102
+ };
103
+
104
+ SignalementCssBuilder.prototype.buildSignalementButton = function() {
105
+ return [
106
+ ".cm-sig-open-btn{display:inline-flex;align-items:center;gap:8px;margin-top:10px;padding:10px 18px;border-radius:12px;border:1.5px solid #0066ff;background:#eff6ff;color:#0066ff;font-size:14px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}",
107
+ ".cm-sig-open-btn svg{width:18px;height:18px;flex-shrink:0}",
108
+ ".cm-sig-open-btn:hover{background:#0066ff;color:#fff;transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,102,255,.3)}",
109
+ ".cm-sig-open-btn:active{transform:scale(0.97)}"
110
+ ].join("\n");
111
+ };
112
+
113
+ SignalementCssBuilder.prototype.buildMobileOverrides = function() {
114
+ return [
115
+ "@media(max-width:600px){",
116
+ ".cm-sig-cat{padding:8px 14px;font-size:13px}",
117
+ ".cm-sig-thumb,.cm-sig-add{width:72px;height:72px}",
118
+ ".cm-sig-photo-btn{padding:6px 12px;font-size:13px}",
119
+ "}"
120
+ ].join("\n");
121
+ };
122
+
123
+ function GeoLocationManager() {
124
+ this.latitude = null;
125
+ this.longitude = null;
126
+ this.accuracy = null;
127
+ this.status = "unknown";
128
+ this.watchId = null;
129
+ }
130
+
131
+ GeoLocationManager.prototype.isSupported = function() {
132
+ return typeof navigator !== "undefined" && "geolocation" in navigator;
133
+ };
134
+
135
+ GeoLocationManager.prototype.request = function(onUpdate) {
136
+ if (!this.isSupported()) {
137
+ this.status = "unsupported";
138
+ if (onUpdate) onUpdate(this);
139
+ return;
140
+ }
141
+ var self = this;
142
+ navigator.geolocation.getCurrentPosition(
143
+ function(pos) {
144
+ self.latitude = pos.coords.latitude;
145
+ self.longitude = pos.coords.longitude;
146
+ self.accuracy = pos.coords.accuracy;
147
+ self.status = "granted";
148
+ if (onUpdate) onUpdate(self);
149
+ },
150
+ function() {
151
+ self.status = "denied";
152
+ if (onUpdate) onUpdate(self);
153
+ },
154
+ { enableHighAccuracy: true, timeout: 10000, maximumAge: 60000 }
155
+ );
156
+ };
157
+
158
+ GeoLocationManager.prototype.stop = function() {
159
+ if (this.watchId !== null && this.isSupported()) {
160
+ navigator.geolocation.clearWatch(this.watchId);
161
+ this.watchId = null;
162
+ }
163
+ };
164
+
165
+ GeoLocationManager.prototype.toPayload = function() {
166
+ return {
167
+ latitude: this.latitude,
168
+ longitude: this.longitude,
169
+ accuracy: this.accuracy,
170
+ geo_status: this.status
171
+ };
172
+ };
173
+
174
+ var CATEGORIES = [
175
+ { id: "voirie", label: "Voirie", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 21h18"/><path d="M5 21V7l8-4v18"/><path d="M19 21V11l-6-4"/></svg>' },
176
+ { id: "espaces_verts", label: "Espaces verts", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9.5 2A2.5 2.5 0 0112 4.5v15a2.5 2.5 0 01-4.96.44 2.5 2.5 0 01-2.96-3.08 3 3 0 01-.34-5.58 2.5 2.5 0 011.32-4.24 2.5 2.5 0 013.54-.94"/><path d="M14.5 2A2.5 2.5 0 0012 4.5v15a2.5 2.5 0 004.96.44 2.5 2.5 0 002.96-3.08 3 3 0 00.34-5.58 2.5 2.5 0 00-1.32-4.24 2.5 2.5 0 00-3.54-.94"/></svg>' },
177
+ { id: "bruit", label: "Bruit", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg>' },
178
+ { id: "proprete", label: "Propreté", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>' },
179
+ { id: "autre", label: "Autre", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>' }
180
+ ];
181
+
182
+ var MAX_PHOTOS = 5;
183
+ var ICON_PIN = '<svg viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2" style="width:22px;height:22px"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>';
184
+ var ICON_PIN_DENIED = '<svg viewBox="0 0 24 24" fill="none" stroke="#dc2626" stroke-width="2" style="width:22px;height:22px"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>';
185
+
186
+ function SignalementModuleManager(rootEl, events, apiManager, uiManager) {
187
+ this.root = rootEl;
188
+ this.events = events;
189
+ this.api = apiManager;
190
+ this.ui = uiManager;
191
+ this.geo = new GeoLocationManager();
192
+ this.selectedCategory = "";
193
+ this.photoFiles = [];
194
+ this.photoPreviewUrls = [];
195
+ this.contentEl = null;
196
+ this.gridEl = null;
197
+ this.locRow = null;
198
+ this.locGlobe = null;
199
+ this.locCheck = null;
200
+ this.locText = null;
201
+ this.locAddr = null;
202
+ this.gpsToggle = null;
203
+ this.mounted = false;
204
+ }
205
+
206
+ SignalementModuleManager.prototype.injectCSS = function() {
207
+ var builder = new SignalementCssBuilder();
208
+ var styleEl = document.createElement("style");
209
+ styleEl.id = "cm-signalement-css";
210
+ styleEl.textContent = builder.build();
211
+ this.root.appendChild(styleEl);
212
+ };
213
+
214
+ SignalementModuleManager.prototype.mount = function(panelEl, headerEl) {
215
+ if (this.mounted) return;
216
+ this.injectCSS();
217
+
218
+ var tabsBar = document.createElement("div");
219
+ tabsBar.id = "cm-tabs-bar";
220
+ tabsBar.innerHTML = [
221
+ '<button class="cm-tab active" data-tab="chat" type="button">',
222
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
223
+ 'Chat</button>',
224
+ '<button class="cm-tab hidden" data-tab="signalement" type="button">',
225
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>',
226
+ 'Signalement',
227
+ '<button class="cm-tab-close" type="button" aria-label="Fermer l\'onglet signalement">',
228
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
229
+ '</button></button>'
230
+ ].join("");
231
+ headerEl.insertAdjacentElement("afterend", tabsBar);
232
+ this.tabsBar = tabsBar;
233
+
234
+ var content = document.createElement("div");
235
+ content.id = "cm-signalement-content";
236
+ content.innerHTML = this.buildFormHTML();
237
+ panelEl.appendChild(content);
238
+ this.contentEl = content;
239
+
240
+ this.gridEl = content.querySelector(".cm-sig-grid");
241
+ this.locRow = content.querySelector(".cm-sig-loc-row");
242
+ this.locGlobe = content.querySelector(".cm-sig-loc-globe");
243
+ this.locCheck = content.querySelector(".cm-sig-loc-check");
244
+ this.locText = content.querySelector(".cm-sig-loc-text");
245
+ this.locAddr = content.querySelector(".cm-sig-loc-addr");
246
+ this.gpsToggle = content.querySelector(".cm-sig-toggle input");
247
+
248
+ this.bindEvents(tabsBar, content);
249
+ this.mounted = true;
250
+ };
251
+
252
+ SignalementModuleManager.prototype.buildFormHTML = function() {
253
+ var catsHtml = CATEGORIES.map(function(cat) {
254
+ return '<button class="cm-sig-cat" data-cat="' + cat.id + '" type="button">' + cat.icon + cat.label + '</button>';
255
+ }).join("");
256
+
257
+ return [
258
+ '<div class="cm-signalement-scroll">',
259
+ '<div class="cm-sig-section"><label class="cm-sig-label">Catégorie <span class="cm-sig-label-opt">(optionnel)</span></label>',
260
+ '<div class="cm-sig-cats">' + catsHtml + '</div></div>',
261
+ '<div class="cm-sig-section"><label class="cm-sig-label">Photos</label>',
262
+ '<div class="cm-sig-photo-actions">',
263
+ '<button class="cm-sig-photo-btn" data-action="photo" type="button"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>Photo</button>',
264
+ '<button class="cm-sig-photo-btn" data-action="camera" type="button"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>Caméra</button>',
265
+ '</div>',
266
+ '<div class="cm-sig-grid">',
267
+ '<button class="cm-sig-add" type="button" aria-label="Ajouter une photo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>',
268
+ '</div></div>',
269
+ '<div class="cm-sig-section"><div class="cm-sig-loc-row">',
270
+ '<div class="cm-sig-loc-status"><div class="cm-sig-loc-globe">' + ICON_PIN + '<span class="cm-sig-loc-check">\u2713</span></div>',
271
+ '<div class="cm-sig-loc-info"><span class="cm-sig-loc-text">Position GPS en attente…</span><span class="cm-sig-loc-addr"></span></div></div>',
272
+ '<label class="cm-sig-toggle"><input type="checkbox" checked><span class="cm-sig-toggle-slider"></span></label>',
273
+ '</div></div>',
274
+ '</div>'
275
+ ].join("");
276
+ };
277
+
278
+ SignalementModuleManager.prototype.bindEvents = function(tabsBar, content) {
279
+ var self = this;
280
+
281
+ tabsBar.querySelectorAll(".cm-tab").forEach(function(tab) {
282
+ tab.addEventListener("click", function() {
283
+ if (tab.classList.contains("hidden")) return;
284
+ self.switchTab(tab.getAttribute("data-tab"));
285
+ });
286
+ });
287
+
288
+ var closeBtn = tabsBar.querySelector(".cm-tab-close");
289
+ if (closeBtn) closeBtn.addEventListener("click", function(e) {
290
+ e.stopPropagation();
291
+ self.close();
292
+ });
293
+
294
+ content.querySelectorAll(".cm-sig-cat").forEach(function(cat) {
295
+ cat.addEventListener("click", function() {
296
+ content.querySelectorAll(".cm-sig-cat").forEach(function(c) { c.classList.remove("active"); });
297
+ cat.classList.add("active");
298
+ self.selectedCategory = cat.getAttribute("data-cat");
299
+ });
300
+ });
301
+
302
+ this.bindDragScroll(content.querySelector(".cm-sig-cats"));
303
+
304
+ content.querySelector('[data-action="photo"]').addEventListener("click", function() { self.triggerFileInput(false); });
305
+ content.querySelector('[data-action="camera"]').addEventListener("click", function() { self.triggerFileInput(true); });
306
+ content.querySelector(".cm-sig-add").addEventListener("click", function() { self.triggerFileInput(false); });
307
+
308
+ if (this.gpsToggle) {
309
+ this.gpsToggle.addEventListener("change", function() {
310
+ if (self.gpsToggle.checked) {
311
+ self.requestGPS();
312
+ } else {
313
+ self.geo.stop();
314
+ self.geo.status = "denied";
315
+ self.updateGPSDisplay();
316
+ }
317
+ });
318
+ }
319
+ };
320
+
321
+ SignalementModuleManager.prototype.bindDragScroll = function(el) {
322
+ if (!el) return;
323
+ var isDown = false, startX, scrollLeft;
324
+ el.style.cursor = "grab";
325
+ el.addEventListener("mousedown", function(e) {
326
+ isDown = true; el.style.cursor = "grabbing";
327
+ startX = e.pageX - el.offsetLeft; scrollLeft = el.scrollLeft;
328
+ e.preventDefault();
329
+ });
330
+ el.addEventListener("mouseleave", function() { isDown = false; el.style.cursor = "grab"; });
331
+ el.addEventListener("mouseup", function() { isDown = false; el.style.cursor = "grab"; });
332
+ el.addEventListener("mousemove", function(e) {
333
+ if (!isDown) return;
334
+ el.scrollLeft = scrollLeft - ((e.pageX - el.offsetLeft) - startX);
335
+ });
336
+ };
337
+
338
+ SignalementModuleManager.prototype.switchTab = function(tabName) {
339
+ var isSignalement = tabName === "signalement";
340
+ this.tabsBar.querySelectorAll(".cm-tab").forEach(function(t) {
341
+ t.classList.toggle("active", t.getAttribute("data-tab") === tabName);
342
+ });
343
+
344
+ var chatElements = this.root.querySelectorAll("#cm-messages, #cm-typing, #cm-error, #cm-disclaimer, #cm-transparency");
345
+ chatElements.forEach(function(el) { el.style.display = isSignalement ? "none" : ""; });
346
+
347
+ var form = this.root.querySelector("#cm-form");
348
+ if (form) {
349
+ var input = form.querySelector("#cm-input");
350
+ if (input) input.placeholder = isSignalement ? "Décrivez votre signalement\u2026" : "Posez votre question\u2026";
351
+ }
352
+
353
+ this.contentEl.classList.toggle("active", isSignalement);
354
+ this.contentEl.style.display = isSignalement ? "flex" : "none";
355
+ };
356
+
357
+ SignalementModuleManager.prototype.open = function(prefill) {
358
+ var sigTab = this.tabsBar.querySelector('[data-tab="signalement"]');
359
+ sigTab.classList.remove("hidden");
360
+ this.tabsBar.classList.add("visible");
361
+ this.switchTab("signalement");
362
+
363
+ if (prefill) {
364
+ if (prefill.category) this.preselectCategory(prefill.category);
365
+ if (prefill.description) {
366
+ var input = this.root.querySelector("#cm-input");
367
+ if (input) { input.value = prefill.description; input.dispatchEvent(new Event("input", { bubbles: true })); }
368
+ }
369
+ }
370
+
371
+ this.requestGPS();
372
+ this.events.emit("module:signalement:open", prefill || {});
373
+ };
374
+
375
+ SignalementModuleManager.prototype.close = function() {
376
+ var sigTab = this.tabsBar.querySelector('[data-tab="signalement"]');
377
+ sigTab.classList.add("hidden");
378
+ this.switchTab("chat");
379
+ this.events.emit("module:signalement:closed", {});
380
+ };
381
+
382
+ SignalementModuleManager.prototype.preselectCategory = function(categoryId) {
383
+ var normalized = String(categoryId || "").toLowerCase().replace(/\s+/g, "_")
384
+ .replace(/é/g, "e").replace(/ê/g, "e");
385
+ this.contentEl.querySelectorAll(".cm-sig-cat").forEach(function(cat) {
386
+ var match = cat.getAttribute("data-cat") === normalized;
387
+ cat.classList.toggle("active", match);
388
+ });
389
+ this.selectedCategory = normalized;
390
+ };
391
+
392
+ SignalementModuleManager.prototype.requestGPS = function() {
393
+ var self = this;
394
+ this.geo.request(function() { self.updateGPSDisplay(); });
395
+ };
396
+
397
+ SignalementModuleManager.prototype.updateGPSDisplay = function() {
398
+ var denied = this.geo.status === "denied" || this.geo.status === "unsupported";
399
+ this.locRow.classList.toggle("denied", denied);
400
+ this.locGlobe.innerHTML = denied ? ICON_PIN_DENIED : ICON_PIN;
401
+ this.locCheck.textContent = denied ? "\u2717" : "\u2713";
402
+ this.locText.textContent = denied ? "Position GPS indisponible" : "Position GPS active";
403
+ this.locAddr.textContent = denied ? "Activez la localisation" : "";
404
+ if (this.gpsToggle) this.gpsToggle.checked = !denied;
405
+ };
406
+
407
+ SignalementModuleManager.prototype.triggerFileInput = function(useCamera) {
408
+ if (this.photoFiles.length >= MAX_PHOTOS) return;
409
+ var input = document.createElement("input");
410
+ input.type = "file";
411
+ input.accept = "image/*";
412
+ if (useCamera) input.setAttribute("capture", "environment");
413
+ input.style.display = "none";
414
+ var self = this;
415
+ input.addEventListener("change", function() {
416
+ if (input.files && input.files[0]) self.addPhoto(input.files[0]);
417
+ input.remove();
418
+ });
419
+ document.body.appendChild(input);
420
+ input.click();
421
+ };
422
+
423
+ SignalementModuleManager.prototype.addPhoto = function(file) {
424
+ if (this.photoFiles.length >= MAX_PHOTOS) return;
425
+ this.photoFiles.push(file);
426
+ var url = URL.createObjectURL(file);
427
+ this.photoPreviewUrls.push(url);
428
+ this.renderPhotoGrid();
429
+ };
430
+
431
+ SignalementModuleManager.prototype.removePhoto = function(index) {
432
+ URL.revokeObjectURL(this.photoPreviewUrls[index]);
433
+ this.photoFiles.splice(index, 1);
434
+ this.photoPreviewUrls.splice(index, 1);
435
+ this.renderPhotoGrid();
436
+ };
437
+
438
+ SignalementModuleManager.prototype.renderPhotoGrid = function() {
439
+ var self = this;
440
+ var html = this.photoPreviewUrls.map(function(url, idx) {
441
+ return '<div class="cm-sig-thumb"><img src="' + url + '" alt="Photo ' + (idx + 1) + '"/>' +
442
+ '<button class="cm-sig-thumb-rm" data-idx="' + idx + '" type="button" aria-label="Supprimer">\u00d7</button></div>';
443
+ }).join("");
444
+
445
+ if (this.photoFiles.length < MAX_PHOTOS) {
446
+ html += '<button class="cm-sig-add" type="button" aria-label="Ajouter une photo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>';
447
+ }
448
+ this.gridEl.innerHTML = html;
449
+
450
+ this.gridEl.querySelectorAll(".cm-sig-thumb-rm").forEach(function(btn) {
451
+ btn.addEventListener("click", function() { self.removePhoto(Number(btn.getAttribute("data-idx"))); });
452
+ });
453
+ var addBtn = this.gridEl.querySelector(".cm-sig-add");
454
+ if (addBtn) addBtn.addEventListener("click", function() { self.triggerFileInput(false); });
455
+ };
456
+
457
+ SignalementModuleManager.prototype.submit = async function() {
458
+ var input = this.root.querySelector("#cm-input");
459
+ var message = input ? input.value.trim() : "";
460
+
461
+ if (!message && this.photoFiles.length === 0) return;
462
+
463
+ var formData = new FormData();
464
+ formData.append("session_id", this.api.state.sessionId || "");
465
+ formData.append("message", message);
466
+ formData.append("category", this.selectedCategory);
467
+
468
+ var geoPayload = this.geo.toPayload();
469
+ if (geoPayload.latitude !== null) formData.append("latitude", String(geoPayload.latitude));
470
+ if (geoPayload.longitude !== null) formData.append("longitude", String(geoPayload.longitude));
471
+ if (geoPayload.accuracy !== null) formData.append("accuracy", String(geoPayload.accuracy));
472
+ formData.append("geo_status", geoPayload.geo_status);
473
+
474
+ for (var i = 0; i < this.photoFiles.length; i++) {
475
+ formData.append("images[]", this.photoFiles[i]);
476
+ }
477
+
478
+ var url = this.api.resolveRuntimeUrl("/v1/modules/signalements/submit");
479
+ var headers = this.api.buildHeaders();
480
+ delete headers["Content-Type"];
481
+
482
+ var response = await fetch(url, { method: "POST", headers: headers, body: formData });
483
+ if (!response.ok) {
484
+ var errBody = await response.text().catch(function() { return ""; });
485
+ throw new Error(errBody || "HTTP " + response.status);
486
+ }
487
+ var result = await response.json();
488
+
489
+ this.resetForm(input);
490
+ this.close();
491
+ this.events.emit("module:signalement:submitted", result);
492
+ return result;
493
+ };
494
+
495
+ SignalementModuleManager.prototype.resetForm = function(input) {
496
+ if (input) { input.value = ""; input.dispatchEvent(new Event("input", { bubbles: true })); }
497
+ this.selectedCategory = "";
498
+ this.contentEl.querySelectorAll(".cm-sig-cat").forEach(function(c) { c.classList.remove("active"); });
499
+ this.photoPreviewUrls.forEach(function(url) { URL.revokeObjectURL(url); });
500
+ this.photoFiles = [];
501
+ this.photoPreviewUrls = [];
502
+ this.renderPhotoGrid();
503
+ };
504
+
505
+ SignalementModuleManager.prototype.createOpenButton = function() {
506
+ var btn = document.createElement("button");
507
+ btn.className = "cm-sig-open-btn";
508
+ btn.type = "button";
509
+ btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>Mon signalement';
510
+ var self = this;
511
+ btn.addEventListener("click", function() { self.open(); });
512
+ return btn;
513
+ };
514
+
515
+ runtime.SignalementModuleManager = SignalementModuleManager;
516
+ runtime.SignalementCssBuilder = SignalementCssBuilder;
517
+ runtime.GeoLocationManager = GeoLocationManager;
518
+ })();