@osfarm/itineraire-technique 1.2.0 → 1.2.1

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.
@@ -132,6 +132,19 @@ class RotationRenderer {
132
132
  this.currentFocusIndex = null;
133
133
  this.noFocusUpdate = false;
134
134
 
135
+ // If some steps have the deprecated attribute field, we add them to the description:
136
+ self.data.steps.map(item => {
137
+ if (item.attributes?.length > 0) {
138
+ item.description += "\n\n";
139
+ item.attributes?.forEach(attr => {
140
+ item.description += `${attr.name} : ${attr.value}\n`;
141
+ });
142
+ }
143
+
144
+ // remove the attributes field to avoid displaying
145
+ delete item.attributes;
146
+ });
147
+
135
148
  if (self.initialLayout == 'horizontal')
136
149
  option = this.getStepsOption();
137
150
  else
@@ -425,13 +438,6 @@ class RotationRenderer {
425
438
  item.name = "Etape " + item.name; // Force the item name to be a string
426
439
 
427
440
  let description = self.getHTMLFormatedDescription(item.description);
428
- if (item.interventions?.length > 0 || item.attributes?.length > 0) {
429
- description += '<br/>';
430
- item.attributes?.forEach(attr => {
431
- description += `<br><b>${attr.name} :</b> ${attr.value}`;
432
- });
433
- }
434
-
435
441
 
436
442
  data.push({
437
443
  name: item.name,
@@ -819,7 +825,7 @@ class RotationRenderer {
819
825
  self.data.steps.forEach((item, index) => {
820
826
 
821
827
  let visibility = 'invisible';
822
- if (item.interventions?.length > 0 || item.attributes?.length > 0)
828
+ if (item.interventions?.length > 0)
823
829
  visibility = "visible";
824
830
 
825
831
  let collapseButton = '<div class="collapse-button ' + visibility + '"><i class="fa fa-chevron-down" aria-hidden="true"></i></div>';
@@ -834,8 +840,7 @@ class RotationRenderer {
834
840
  + '<div class="step_dates">' + dates + '</div>'
835
841
  + '<h4 class="">' + item.name + '<i class="fa fa-pencil step-edit" aria-hidden="true"></i></h4>'
836
842
  + '</div><p class="step_description clearfix">' + self.getHTMLFormatedDescription(item.description) + '</p>'
837
- + '<div class="details">'
838
- + (item.attributes?.length > 0 ? item.attributes.map((attribute) => { return '<p><dt>' + attribute.name + '</dt><dd>' + attribute.value + '</dd></p>' }).join('') : '');
843
+ + '<div class="details">';
839
844
 
840
845
  if (item.interventions?.length > 0) {
841
846
  html += '<h5>Interventions</h5>';
@@ -1109,7 +1114,7 @@ class RotationRenderer {
1109
1114
  hideDelay: 1000,
1110
1115
  extraCssText: "text-wrap: wrap;",
1111
1116
  position: function (pos, params, el, elRect, size) {
1112
- var obj = { top: 10 };
1117
+ var obj = { bottom: 10 };
1113
1118
  obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
1114
1119
  return obj;
1115
1120
  },
@@ -1,217 +1,343 @@
1
- function addInterventionClickEvent() {
2
- let id = getInputValue("interventionId");
3
- let name = getInputValue("interventionName");
4
- let day = getInputValue("interventionDay");
5
- let type = getInputValue("interventionType");
6
- let description = getInputValue("interventionDescription");
7
-
8
- if (id != "") {
9
- selectedStep.updateIntervention(id, day, name, type, description);
10
- } else {
11
- selectedStep.addIntervention(day, name, type, description);
12
-
13
- document.getElementById("newInterventionButton").classList.remove("d-none");
14
- getAndCleanElement("newInterventionContainer");
1
+ /**
2
+ * InterventionTable class - Manages interventions UI and interactions
3
+ */
4
+ class InterventionTable {
5
+
6
+ // Constructor
7
+ constructor(interventionsTopTitle, interventionsBottomTitle, tikaEditorInstance) {
8
+ this.selectedStep = null;
9
+
10
+ this.interventionsTopTitle = interventionsTopTitle;
11
+ this.interventionsBottomTitle = interventionsBottomTitle;
12
+ this.tikaEditorInstance = tikaEditorInstance;
15
13
  }
16
- refreshAllTables();
17
- }
18
14
 
19
- function refreshInterventionsTable() {
20
- let interventionsTopContainer = getAndCleanElement("interventionsTopContainer");
21
- let interventionsBottomContainer = getAndCleanElement("interventionsBottomContainer");
15
+ /**
16
+ * Setup the interventions table div dynamically
17
+ */
18
+ setupDiv() {
19
+
20
+ // Check if the div already exists
21
+ if ($('#interventionsTable').length > 0) {
22
+ return; // Already created
23
+ }
22
24
 
23
- if (selectedStep && selectedStep.getStep().interventions) {
24
- // Sort all interventions by day
25
- selectedStep.getStep().interventions = selectedStep.getStep().interventions.sort((a, b) => a.day - b.day);
25
+ const interventionsTableDiv = $(`
26
+ <div id="interventionsTable" class="row card-holder">
27
+ <div class="col-12">
28
+ <h5>Interventions</h5>
29
+ <div class="row">
30
+ <p id="interventionsTopName" class="h6">${this.interventionsTopTitle}</p>
31
+ <div id="interventionsTopContainer" class="container"></div>
32
+ </div>
33
+ <hr class="my-2">
34
+ <div class="row">
35
+ <p id="interventionsBottomName" class="h6">${this.interventionsBottomTitle}</p>
36
+ <div id="interventionsBottomContainer" class="container"></div>
37
+ </div>
38
+
39
+ <button id="newInterventionButton" type="button"
40
+ class="btn btn-primary primary-button w-100"><i class="fa fa-plus-square"
41
+ aria-hidden="true"></i> Ajouter</button>
42
+ <div id="newInterventionContainer"></div>
43
+ </div>
44
+ </div>
45
+ `);
46
+
47
+ // Insert after the step's details
48
+ $('#cropDetailView').after(interventionsTableDiv);
26
49
 
27
- selectedStep.getStep().interventions.forEach((intervention) => {
28
- const rowDiv = createInterventionRow(intervention);
50
+ const self = this;
29
51
 
30
- if (intervention.type === crops.options.title_top_interventions) {
31
- interventionsTopContainer.appendChild(rowDiv);
32
- } else {
33
- interventionsBottomContainer.appendChild(rowDiv);
34
- }
52
+ $('#newInterventionButton').on('click', function(e) {
53
+ e.preventDefault();
54
+ self.showInterventionForm();
35
55
  });
36
56
  }
37
- }
38
57
 
39
- function createInterventionRow(intervention) {
40
- let rowDiv = document.createElement("div");
41
- rowDiv.className = "row mb-2 intervention-row editable-row position-relative";
42
-
43
- let nameValueDiv = createInterventionNameAndValueColumn(intervention);
44
- rowDiv.appendChild(nameValueDiv);
45
-
46
- addEditAndRemoveButtons(
47
- rowDiv,
48
- intervention.id,
49
- function () {
50
- createInterventionForm(intervention.id, intervention.day, intervention.name, intervention.type, intervention.description, rowDiv);
51
- },
52
- function(id) {
53
- selectedStep.removeIntervention(id);
54
- refreshInterventionsTable();
55
- renderChart();
56
- },
57
- function(id) {
58
- duplicateIntervention(id);
59
- refreshInterventionsTable();
60
- renderChart();
61
- },
62
- 'btn-group-vertical'
63
- );
64
-
65
- return rowDiv;
66
- }
58
+ getAndCleanElement(elementId) {
59
+ let element = document.getElementById(elementId);
60
+ element.innerHTML = "";
61
+ return element;
62
+ }
63
+
64
+ refreshInterventionsTable(selectedStep) {
65
+ this.selectedStep = selectedStep;
66
+
67
+ let interventionsTopContainer = this.getAndCleanElement("interventionsTopContainer");
68
+ let interventionsBottomContainer = this.getAndCleanElement("interventionsBottomContainer");
69
+
70
+ if (this.selectedStep.getStep().interventions) {
71
+ // Sort all interventions by day
72
+ this.selectedStep.getStep().interventions = this.selectedStep.getStep().interventions.sort((a, b) => a.day - b.day);
73
+
74
+ this.selectedStep.getStep().interventions.forEach((intervention) => {
75
+ const rowDiv = this.createInterventionRow(intervention);
76
+
77
+ if (intervention.type === 'intervention_top') {
78
+ $("#interventionsTopContainer").append(rowDiv);
79
+ } else {
80
+ $("#interventionsBottomContainer").append(rowDiv);
81
+ }
82
+ });
83
+ }
84
+ }
85
+
86
+ addEditAndRemoveButtons(rowDiv, deleteId, editFunction, deleteFunction, duplicateFunction, style="btn-group") {
87
+ rowDiv = $(rowDiv);
88
+
89
+ let actionContainer = $(`<div class="col-auto edit-buttons m-1 ${style}" role="group"></div>`);
90
+
91
+ rowDiv.append(actionContainer);
67
92
 
68
- function createInterventionNameAndValueColumn(intervention) {
69
- let absoluteDate = "";
70
- if (selectedStep && selectedStep.getStep().startDate) {
71
- const stepStartDate = new Date(selectedStep.getStep().startDate);
72
- const interventionDate = new Date(stepStartDate);
73
- interventionDate.setDate(stepStartDate.getDate() + parseInt(intervention.day));
74
- absoluteDate = interventionDate.toLocaleDateString('fr-FR', {
75
- month: "short",
76
- day: "numeric",
93
+ actionContainer.append($('<button class="edit-button btn btn-outline-primary p-2"><i class="fa fa-pencil"></i></button>').click(function(event) {
94
+ event.stopPropagation();
95
+ editFunction();
96
+ }));
97
+
98
+ rowDiv.find('.col').click(function(event) {
99
+ event.stopPropagation();
100
+ editFunction();
77
101
  });
102
+
103
+ if (duplicateFunction != null) {
104
+ actionContainer.append($('<button class="btn btn-outline-secondary p-2"><i class="fa fa-copy"></i></button>').click(function (event) {
105
+ event.stopPropagation();
106
+ duplicateFunction(deleteId);
107
+ }));
108
+ }
109
+
110
+ actionContainer.append($('<button class="btn btn-outline-danger p-2"><i class="fa fa-trash"></i></button>').click(function (event) {
111
+ event.stopPropagation();
112
+ deleteFunction(deleteId);
113
+ }));
78
114
  }
79
-
80
- let nameValueDiv = document.createElement("div");
81
- nameValueDiv.className = "col";
82
- nameValueDiv.innerHTML = `<strong>${intervention.name}</strong> (${absoluteDate})</br> ${intervention.description}`;
83
115
 
84
- return nameValueDiv;
85
- }
116
+ createInterventionRow(intervention) {
117
+ const self = this;
118
+ let rowDiv = document.createElement("div");
119
+ rowDiv.className = "row mb-2 intervention-row editable-row position-relative";
120
+ rowDiv.id = `interventionRow_${intervention.id}`;
86
121
 
87
- function createInterventionForm(id, day, name, type, description, row) {
88
- id = id || "";
89
- day = day || "";
90
- name = name || "";
91
- type = type || "";
92
- description = description || "";
93
-
94
- // Calculate absolute date from relative day
95
- let absoluteDate = "";
96
- if (day == "")
97
- day = 0;
98
-
99
- if (selectedStep && selectedStep.getStep().startDate) {
100
- const stepStartDate = new Date(selectedStep.getStep().startDate);
101
- const interventionDate = new Date(stepStartDate);
102
- interventionDate.setDate(stepStartDate.getDate() + parseInt(day));
103
- absoluteDate = interventionDate.toISOString().split('T')[0];
122
+ let nameValueDiv = self.createInterventionNameAndValueColumn(intervention);
123
+ rowDiv.appendChild(nameValueDiv);
124
+
125
+ this.addEditAndRemoveButtons(
126
+ rowDiv,
127
+ intervention.id,
128
+ function () {
129
+ self.showInterventionForm(intervention, rowDiv);
130
+ },
131
+ function(id) {
132
+ self.selectedStep.removeIntervention(id);
133
+ $(`#interventionRow_${id}`).remove();
134
+ self.tikaEditorInstance.renderChart();
135
+ },
136
+ function(id) {
137
+ const newIntervention = self.duplicateIntervention(id);
138
+ const div = self.createInterventionRow(newIntervention);
139
+ if (newIntervention.type === 'intervention_top') {
140
+ $("#interventionsTopContainer").append(div);
141
+ } else {
142
+ $("#interventionsBottomContainer").append(div);
143
+ }
144
+ self.tikaEditorInstance.renderChart();
145
+ },
146
+ 'btn-group-vertical'
147
+ );
148
+
149
+ return rowDiv;
104
150
  }
105
151
 
106
- const formContainer = document.createElement("div");
107
- formContainer.innerHTML =
108
- `<form id="interventionForm">
109
- <div class="row card-white mb-2">
110
- <input type="hidden" id="interventionId" value="${id}">
111
- <div class="col-12 mb-2">
112
- <label for="interventionName" class="form-label">Nom</label>
113
- <input type="text" id="interventionName" class="form-control" placeholder="Nom" value="${name}">
114
- </div>
115
- <div class="col-12 mb-2">
116
- <textarea id="interventionDescription" class="form-control"
117
- placeholder="Ajouter une description">${description}</textarea>
118
- </div>
119
- <div class="col-4 mb-2">
120
- <label for="interventionDay" class="form-label">Jour relatif</label>
121
- <input type="number" id="interventionDay" class="form-control text-right" placeholder="Jour"
122
- value="${day}">
123
- </div>
124
- <div class="col-8 mb-2">
125
- <label for="interventionDate" class="form-label">Date absolue</label>
126
- <input type="date" id="interventionDate" class="form-control" value="${absoluteDate}">
127
- </div>
128
- <div class="col-12 mb-2">
129
- <select id="interventionType" class="form-select" aria-label="Type">
130
- <option value="intervention_top"
131
- ${type === "intervention_top" ? "selected" : ""}>${crops.options.title_top_interventions}</option>
132
- <option value="intervention_bottom"
133
- ${type === "intervention_bottom" ? "selected" : ""}>${crops.options.title_bottom_interventions}</option>
134
- </select>
135
- </div>
152
+ createInterventionNameAndValueColumn(intervention) {
153
+ let absoluteDate = "";
154
+ if (this.selectedStep && this.selectedStep.getStep().startDate) {
155
+ const stepStartDate = new Date(this.selectedStep.getStep().startDate);
156
+ const interventionDate = new Date(stepStartDate);
157
+ interventionDate.setDate(stepStartDate.getDate() + parseInt(intervention.day));
158
+ absoluteDate = interventionDate.toLocaleDateString('fr-FR', {
159
+ month: "short",
160
+ day: "numeric",
161
+ });
162
+ }
163
+
164
+ let nameValueDiv = document.createElement("div");
165
+ nameValueDiv.className = "col";
166
+ nameValueDiv.innerHTML = `<strong>${intervention.name}</strong> (${absoluteDate})</br> ${intervention.description}`;
136
167
 
137
- <div class="col">
138
- <button type="button" onclick="addInterventionClickEvent()"
139
- class="w-100 btn btn-outline-primary primary-button">Valider</button>
140
- </div>
141
- </div>
142
- </form>
143
- `;
144
-
145
- if (row) { //we are editing an intervention
146
- row.replaceWith(formContainer);
147
- } else { //we are adding an intervention
148
- document.getElementById("newInterventionContainer").appendChild(formContainer);
149
- document.getElementById("newInterventionButton").classList.add("d-none");
168
+ return nameValueDiv;
150
169
  }
151
170
 
152
- // Add event listeners for date synchronization
153
- setupInterventionDateListeners();
171
+ showInterventionForm(intervention, row) {
172
+ const self = this;
173
+ let id = intervention?.id || "";
174
+ let day = intervention?.day || "";
175
+ let name = intervention?.name || "";
176
+ let type = intervention?.type || "";
177
+ let description = intervention?.description || "";
154
178
 
155
- $("#interventionName").focus();
156
- }
179
+ // Calculate absolute date from relative day
180
+ let absoluteDate = "";
181
+ if (day === "")
182
+ day = 0;
183
+
184
+ if (this.selectedStep && this.selectedStep.getStep().startDate) {
185
+ const stepStartDate = new Date(this.selectedStep.getStep().startDate);
186
+ const interventionDate = new Date(stepStartDate);
187
+ interventionDate.setDate(stepStartDate.getDate() + parseInt(day));
188
+ absoluteDate = interventionDate.toISOString().split('T')[0];
189
+ }
157
190
 
158
- function setupInterventionDateListeners() {
159
- // When relative day changes, update absolute date
160
- $("#interventionDay").on("input change", function() {
161
- updateAbsoluteDateFromRelative();
162
- });
191
+ const formContainer = document.createElement("div");
192
+ formContainer.innerHTML =
193
+ `<form id="interventionForm">
194
+ <div class="row card-white mb-2">
195
+ <input type="hidden" id="interventionId" value="${id}">
196
+ <div class="col-12 mb-2">
197
+ <label for="interventionName" class="form-label">Nom</label>
198
+ <input type="text" id="interventionName" class="form-control" placeholder="Nom" value="${name}">
199
+ </div>
200
+ <div class="col-12 mb-2">
201
+ <textarea id="interventionDescription" class="form-control"
202
+ placeholder="Ajouter une description">${description}</textarea>
203
+ </div>
204
+ <div class="col-4 mb-2">
205
+ <label for="interventionDay" class="form-label">Jour relatif</label>
206
+ <input type="number" id="interventionDay" class="form-control text-right" placeholder="Jour"
207
+ value="${day}">
208
+ </div>
209
+ <div class="col-8 mb-2">
210
+ <label for="interventionDate" class="form-label">Date absolue</label>
211
+ <input type="date" id="interventionDate" class="form-control" value="${absoluteDate}">
212
+ </div>
213
+ <div class="col-12 mb-2">
214
+ <select id="interventionType" class="form-select" aria-label="Type">
215
+ <option value="intervention_top"
216
+ ${type === "intervention_top" ? "selected" : ""}>${this.interventionsTopTitle}</option>
217
+ <option value="intervention_bottom"
218
+ ${type === "intervention_bottom" ? "selected" : ""}>${this.interventionsBottomTitle}</option>
219
+ </select>
220
+ </div>
163
221
 
164
- // When absolute date changes, update relative day
165
- $("#interventionDate").on("change", function() {
166
- updateRelativeDayFromAbsolute();
167
- });
168
- }
222
+ <div class="col">
223
+ <button type="button" class="ValidateInterventionFormButton w-100 btn btn-outline-primary primary-button">Valider</button>
224
+ </div>
225
+ </div>
226
+ </form>
227
+ `;
169
228
 
170
- function updateAbsoluteDateFromRelative() {
171
- const relativeDay = $("#interventionDay").val();
172
- if (relativeDay == "")
173
- relativeDay = 0;
229
+ // Add the addInterventionClickEvent listener to the button
230
+ const form = $(formContainer);
231
+ form.find(".ValidateInterventionFormButton").on("click", (e) => {
232
+ e.preventDefault();
174
233
 
175
- if (selectedStep && selectedStep.getStep().startDate) {
176
- const stepStartDate = new Date(selectedStep.getStep().startDate);
177
- const interventionDate = new Date(stepStartDate);
178
- interventionDate.setDate(stepStartDate.getDate() + parseInt(relativeDay));
179
-
180
- const absoluteDateStr = interventionDate.toISOString().split('T')[0];
181
- $("#interventionDate").val(absoluteDateStr);
182
- }
183
- }
234
+ let id = form.find("#interventionId").val();
235
+ let name = form.find("#interventionName").val();
236
+ let day = form.find("#interventionDay").val();
237
+ let type = form.find("#interventionType").val();
238
+ let description = form.find("#interventionDescription").val();
239
+
240
+ if (id != "") {
241
+ intervention.name = name;
242
+ intervention.day = day;
243
+ intervention.type = type;
244
+ intervention.description = description;
245
+
246
+ // Also update the row display
247
+ const updatedRowDiv = this.createInterventionRow(this.selectedStep.getStep().interventions.find(itv => itv.id === id));
248
+ $(formContainer).replaceWith(updatedRowDiv);
249
+
250
+ } else {
251
+ this.selectedStep.addIntervention(day, name, type, description);
252
+
253
+ $("#newInterventionButton").show();
254
+ this.getAndCleanElement("newInterventionContainer");
184
255
 
185
- function updateRelativeDayFromAbsolute() {
186
- const absoluteDate = $("#interventionDate").val();
187
- if (absoluteDate !== "" && selectedStep && selectedStep.getStep().startDate) {
188
- const stepStartDate = new Date(selectedStep.getStep().startDate);
189
- const interventionDate = new Date(absoluteDate);
256
+ // Add the new intervention to the table
257
+ const newIntervention = this.selectedStep.getStep().interventions[this.selectedStep.getStep().interventions.length - 1];
258
+ const newRowDiv = this.createInterventionRow(newIntervention);
259
+ if (newIntervention.type === 'intervention_top') {
260
+ $("#interventionsTopContainer").append(newRowDiv);
261
+ } else {
262
+ $("#interventionsBottomContainer").append(newRowDiv);
263
+ }
264
+
265
+ // Remove the form
266
+ formContainer.remove();
267
+ }
268
+
269
+ self.tikaEditorInstance.renderChart();
270
+ });
190
271
 
191
- // Calculate difference in days
192
- const timeDiff = interventionDate.getTime() - stepStartDate.getTime();
193
- const dayDiff = Math.round(timeDiff / (1000 * 60 * 60 * 24));
272
+ if (row) { //we are editing an intervention
273
+ row.replaceWith(formContainer);
274
+ } else { //we are adding an intervention
275
+ $("#newInterventionContainer").append(formContainer);
276
+ $("#newInterventionButton").hide();
277
+ }
278
+
279
+ // Add event listeners for date synchronization
280
+ // When relative day changes, update absolute date
281
+ form.find("#interventionDay").on("input change", function() {
282
+ self.updateAbsoluteDateFromRelative();
283
+ });
284
+
285
+ // When absolute date changes, update relative day
286
+ form.find("#interventionDate").on("change", function() {
287
+ self.updateRelativeDayFromAbsolute();
288
+ });
194
289
 
195
- $("#interventionDay").val(dayDiff);
290
+ form.find("#interventionName").focus();
291
+ }
292
+
293
+ updateAbsoluteDateFromRelative() {
294
+ const relativeDay = $("#interventionDay").val();
295
+ if (relativeDay == "")
296
+ relativeDay = 0;
297
+
298
+ if (this.selectedStep && this.selectedStep.getStep().startDate) {
299
+ const stepStartDate = new Date(this.selectedStep.getStep().startDate);
300
+ const interventionDate = new Date(stepStartDate);
301
+ interventionDate.setDate(stepStartDate.getDate() + parseInt(relativeDay));
302
+
303
+ const absoluteDateStr = interventionDate.toISOString().split('T')[0];
304
+ $("#interventionDate").val(absoluteDateStr);
305
+ }
196
306
  }
197
- }
198
307
 
199
- function duplicateIntervention(interventionId) {
200
- if (!selectedStep) return;
201
-
202
- // Find the intervention to duplicate
203
- let originalIntervention = selectedStep.getStep().interventions.find(interv => interv.id === interventionId);
204
- if (!originalIntervention) return;
205
-
206
- // Create a copy of the intervention
207
- let newIntervention = {
208
- id: crypto.randomUUID(),
209
- day: Number(originalIntervention.day) + 15, // Offset by 15 days to avoid overlap
210
- name: originalIntervention.name,
211
- type: originalIntervention.type,
212
- description: originalIntervention.description
213
- };
214
-
215
- // Add the duplicated intervention to the selected step
216
- selectedStep.getStep().interventions.push(newIntervention);
217
- }
308
+ updateRelativeDayFromAbsolute() {
309
+ const absoluteDate = $("#interventionDate").val();
310
+ if (absoluteDate !== "" && this.selectedStep && this.selectedStep.getStep().startDate) {
311
+ const stepStartDate = new Date(this.selectedStep.getStep().startDate);
312
+ const interventionDate = new Date(absoluteDate);
313
+
314
+ // Calculate difference in days
315
+ const timeDiff = interventionDate.getTime() - stepStartDate.getTime();
316
+ const dayDiff = Math.round(timeDiff / (1000 * 60 * 60 * 24));
317
+
318
+ $("#interventionDay").val(dayDiff);
319
+ }
320
+ }
321
+
322
+ duplicateIntervention(interventionId) {
323
+ if (!this.selectedStep) return;
324
+
325
+ // Find the intervention to duplicate
326
+ let originalIntervention = this.selectedStep.getStep().interventions.find(interv => interv.id === interventionId);
327
+ if (!originalIntervention) return;
328
+
329
+ // Create a copy of the intervention
330
+ let newIntervention = {
331
+ id: crypto.randomUUID(),
332
+ day: Number(originalIntervention.day) + 15, // Offset by 15 days to avoid overlap
333
+ name: originalIntervention.name,
334
+ type: originalIntervention.type,
335
+ description: originalIntervention.description
336
+ };
337
+
338
+ // Add the duplicated intervention to the selected step
339
+ this.selectedStep.getStep().interventions.push(newIntervention);
340
+
341
+ return newIntervention;
342
+ }
343
+ }