oceanhelm 0.0.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.
@@ -0,0 +1,2134 @@
1
+ import { openBlock as r, createElementBlock as a, normalizeClass as h, createElementVNode as t, toDisplayString as d, createCommentVNode as u, Fragment as f, renderList as g, withModifiers as C, createTextVNode as b, renderSlot as T, withDirectives as c, vShow as _, normalizeStyle as S, createStaticVNode as k, vModelText as y, vModelSelect as w, vModelCheckbox as D } from "vue";
2
+ const x = (i, e) => {
3
+ const l = i.__vccOpts || i;
4
+ for (const [v, n] of e)
5
+ l[v] = n;
6
+ return l;
7
+ }, P = {
8
+ name: "ConfigurableSidebar",
9
+ props: {
10
+ // Brand configuration
11
+ brandName: {
12
+ type: String,
13
+ default: "OceanHelm"
14
+ },
15
+ logoIcon: {
16
+ type: String,
17
+ default: "bi bi-water"
18
+ },
19
+ showLogo: {
20
+ type: Boolean,
21
+ default: !0
22
+ },
23
+ // Menu items configuration
24
+ menuItems: {
25
+ type: Array,
26
+ required: !0,
27
+ default: () => []
28
+ },
29
+ // User profile for role-based filtering
30
+ userProfile: {
31
+ type: Object,
32
+ default: () => ({})
33
+ },
34
+ // Sidebar behavior
35
+ responsive: {
36
+ type: Boolean,
37
+ default: !0
38
+ },
39
+ // Custom classes
40
+ customClasses: {
41
+ type: String,
42
+ default: ""
43
+ },
44
+ // Permission checker function
45
+ permissionChecker: {
46
+ type: Function,
47
+ default: null
48
+ }
49
+ },
50
+ computed: {
51
+ sidebarClasses() {
52
+ return this.customClasses;
53
+ },
54
+ filteredMenuItems() {
55
+ return this.menuItems.filter((i) => this.hasPermission(i));
56
+ }
57
+ },
58
+ mounted() {
59
+ this.responsive && this.initializeResponsiveBehavior();
60
+ },
61
+ methods: {
62
+ // Permission checking
63
+ hasPermission(i) {
64
+ return this.permissionChecker ? this.permissionChecker(i, this.userProfile) : !i.roles || i.roles.length === 0 ? !0 : i.roles.includes(this.userProfile.role);
65
+ },
66
+ // Navigation handling
67
+ handleNavigation(i) {
68
+ var e;
69
+ this.$emit("navigate", i), i.href && !i.preventDefault && (i.external ? window.open(i.href, "_blank") : (e = this.$router) == null || e.push(i.href));
70
+ },
71
+ // Action handling
72
+ handleAction(i) {
73
+ this.$emit("action", i);
74
+ },
75
+ // Item click handling
76
+ handleItemClick(i) {
77
+ this.$emit("item-click", i), i.type;
78
+ },
79
+ // Responsive behavior
80
+ initializeResponsiveBehavior() {
81
+ const i = document.getElementById("sidebarToggle"), e = document.getElementById("sidebar"), l = document.getElementById("content");
82
+ !i || !e || !l || (window.innerWidth >= 768 && (e.classList.toggle("active"), l.classList.toggle("active")), i.addEventListener("click", () => {
83
+ e.classList.toggle("active"), l.classList.toggle("active");
84
+ }), document.addEventListener("click", (v) => {
85
+ const n = e.contains(v.target), o = i.contains(v.target);
86
+ !n && !o && window.innerWidth < 768 && e.classList.contains("active") && (e.classList.remove("active"), l.classList.remove("active"));
87
+ }));
88
+ }
89
+ },
90
+ emits: ["navigate", "action", "item-click"]
91
+ }, M = {
92
+ key: 0,
93
+ class: "logo d-flex align-items-center left"
94
+ }, E = { class: "list-unstyled components mt-4" }, V = ["onClick"], N = ["href", "onClick"], L = ["onClick"], F = {
95
+ class: "dropdown-toggle",
96
+ type: "button",
97
+ "data-bs-toggle": "dropdown",
98
+ "aria-expanded": "false"
99
+ }, U = {
100
+ class: "dropdown-menu",
101
+ "aria-labelledby": "dropdownMenuLink"
102
+ }, I = ["onClick"], R = {
103
+ key: 3,
104
+ class: "dropdown-divider"
105
+ }, O = { key: 4 };
106
+ function B(i, e, l, v, n, o) {
107
+ return r(), a("nav", {
108
+ id: "sidebar",
109
+ class: h(o.sidebarClasses)
110
+ }, [
111
+ l.showLogo ? (r(), a("div", M, [
112
+ t("i", {
113
+ class: h([l.logoIcon, "me-2"])
114
+ }, null, 2),
115
+ t("span", null, d(l.brandName), 1)
116
+ ])) : u("", !0),
117
+ t("ul", E, [
118
+ (r(!0), a(f, null, g(o.filteredMenuItems, (s, m) => (r(), a("li", {
119
+ key: m,
120
+ class: h({ active: s.active, dropdown: s.type === "dropdown" }),
121
+ onClick: (p) => o.handleItemClick(s)
122
+ }, [
123
+ s.type === "link" ? (r(), a("a", {
124
+ key: 0,
125
+ href: s.href || "#",
126
+ onClick: C((p) => o.handleNavigation(s), ["prevent"])
127
+ }, [
128
+ s.icon ? (r(), a("i", {
129
+ key: 0,
130
+ class: h(s.icon)
131
+ }, null, 2)) : u("", !0),
132
+ b(" " + d(s.label), 1)
133
+ ], 8, N)) : s.type === "button" ? (r(), a("a", {
134
+ key: 1,
135
+ onClick: C((p) => o.handleAction(s), ["prevent"]),
136
+ style: { cursor: "pointer" }
137
+ }, [
138
+ s.icon ? (r(), a("i", {
139
+ key: 0,
140
+ class: h(s.icon)
141
+ }, null, 2)) : u("", !0),
142
+ b(" " + d(s.label), 1)
143
+ ], 8, L)) : s.type === "dropdown" ? (r(), a(f, { key: 2 }, [
144
+ t("a", F, [
145
+ s.icon ? (r(), a("i", {
146
+ key: 0,
147
+ class: h(s.icon)
148
+ }, null, 2)) : u("", !0),
149
+ b(" " + d(s.label), 1)
150
+ ]),
151
+ t("div", U, [
152
+ (r(!0), a(f, null, g(s.children, (p, A) => (r(), a("a", {
153
+ key: A,
154
+ class: "dropdown-item black",
155
+ onClick: C((Ei) => o.handleAction(p), ["prevent"]),
156
+ style: { cursor: "pointer" }
157
+ }, d(p.label), 9, I))), 128))
158
+ ])
159
+ ], 64)) : s.type === "separator" ? (r(), a("div", R)) : s.type === "text" ? (r(), a("a", O, d(s.label), 1)) : u("", !0)
160
+ ], 10, V))), 128))
161
+ ]),
162
+ T(i.$slots, "footer", {}, void 0, !0)
163
+ ], 2);
164
+ }
165
+ const H = /* @__PURE__ */ x(P, [["render", B], ["__scopeId", "data-v-5c9320f4"]]);
166
+ const q = {
167
+ name: "VesselList",
168
+ props: {
169
+ // Required props
170
+ vessels: {
171
+ type: Array,
172
+ required: !0,
173
+ default: () => []
174
+ },
175
+ userProfile: {
176
+ type: Object,
177
+ required: !0,
178
+ default: () => ({ role: "viewer", vessel: null })
179
+ },
180
+ // Optional props
181
+ loading: {
182
+ type: Boolean,
183
+ default: !1
184
+ },
185
+ currentRoute: {
186
+ type: String,
187
+ default: "dashboard"
188
+ // 'dashboard', 'maintenanceroute', 'crewroute'
189
+ },
190
+ // Configuration props
191
+ config: {
192
+ type: Object,
193
+ default: () => ({
194
+ enableAdd: !0,
195
+ enableEdit: !0,
196
+ enableDelete: !0,
197
+ enableStatusToggle: !0,
198
+ showCertifications: !0
199
+ })
200
+ }
201
+ },
202
+ emits: [
203
+ "vessel-add",
204
+ "vessel-click",
205
+ "vessel-edit",
206
+ "vessel-delete",
207
+ "vessel-toggle-status",
208
+ "vessel-navigate",
209
+ "access-denied"
210
+ ],
211
+ computed: {
212
+ activeVesselsCount() {
213
+ return this.vessels.filter((i) => i.status === "Active").length;
214
+ },
215
+ inactiveVesselsCount() {
216
+ return this.vessels.filter((i) => i.status === "Inactive").length;
217
+ },
218
+ canAddVessel() {
219
+ return this.config.enableAdd && (this.userProfile.role === "owner" || this.userProfile.role === "staff");
220
+ }
221
+ },
222
+ methods: {
223
+ // Event handlers that emit to parent
224
+ handleAddVessel() {
225
+ if (!this.canAddVessel) {
226
+ this.handleAccessDenied("add vessel");
227
+ return;
228
+ }
229
+ this.$emit("vessel-add");
230
+ },
231
+ handleVesselClick(i) {
232
+ const e = {
233
+ vessel: i,
234
+ route: this.currentRoute,
235
+ id: i.registrationNumber,
236
+ name: i.name
237
+ };
238
+ this.currentRoute === "dashboard" ? this.$emit("vessel-click", i) : this.$emit("vessel-navigate", e);
239
+ },
240
+ handleDeleteVessel(i) {
241
+ if (!this.grantAccess(i)) {
242
+ this.handleAccessDenied("delete vessel");
243
+ return;
244
+ }
245
+ this.config.enableDelete && this.$emit("vessel-delete", i);
246
+ },
247
+ handleToggleStatus(i) {
248
+ if (!this.grantAccess(i)) {
249
+ this.handleAccessDenied("change vessel status");
250
+ return;
251
+ }
252
+ this.config.enableStatusToggle && this.$emit("vessel-toggle-status", i);
253
+ },
254
+ handleEditVessel(i) {
255
+ if (!this.grantAccess(i)) {
256
+ this.handleAccessDenied("edit vessel");
257
+ return;
258
+ }
259
+ this.config.enableEdit && this.$emit("vessel-edit", i);
260
+ },
261
+ handleAccessDenied(i) {
262
+ this.$emit("access-denied", { action: i, userProfile: this.userProfile });
263
+ },
264
+ // Utility methods (keep these in component as they're UI-related)
265
+ statusClass(i) {
266
+ return `status-${(i == null ? void 0 : i.toLowerCase()) || ""}`;
267
+ },
268
+ grantAccess(i) {
269
+ const { role: e, vessel: l } = this.userProfile;
270
+ return e === "owner" || e === "staff" || e === "captain" && l === i.name;
271
+ },
272
+ getDaysToExpiry(i) {
273
+ if (!i)
274
+ return null;
275
+ const e = /* @__PURE__ */ new Date(), v = new Date(i) - e;
276
+ return Math.ceil(v / (1e3 * 60 * 60 * 24));
277
+ },
278
+ getExpiryClass(i) {
279
+ const e = this.getDaysToExpiry(i);
280
+ return e === null ? "" : e < 30 ? "cert-critical" : e < 90 ? "cert-warning" : "";
281
+ }
282
+ }
283
+ }, j = { class: "row mb-3" }, $ = { class: "col-md-4" }, Q = { class: "card border-0 shadow-sm" }, z = { class: "card-body d-flex align-items-center" }, Y = { class: "mt-2 mb-0" }, K = { class: "col-md-4" }, W = { class: "card border-0 shadow-sm" }, G = { class: "card-body d-flex align-items-center" }, J = { class: "mt-2 mb-0" }, X = {
284
+ key: 0,
285
+ class: "col-md-4"
286
+ }, Z = {
287
+ key: 0,
288
+ class: "text-center py-4"
289
+ }, ee = {
290
+ key: 1,
291
+ class: "alert alert-primary",
292
+ role: "alert"
293
+ }, te = {
294
+ key: 2,
295
+ class: "row"
296
+ }, se = ["onClick"], ie = { class: "card-body d-flex align-items-center" }, ne = { class: "flex-grow-1" }, le = { class: "d-flex justify-content-between align-items-center mb-2" }, oe = { class: "card-title mb-0" }, re = { class: "row" }, ae = { class: "col-6" }, de = { class: "mb-0" }, ce = { class: "col-6" }, ue = { class: "mb-0" }, me = { class: "action-icon left delete" }, ve = ["onClick"], he = ["onClick"];
297
+ function fe(i, e, l, v, n, o) {
298
+ return r(), a(f, null, [
299
+ t("div", j, [
300
+ t("div", $, [
301
+ t("div", Q, [
302
+ t("div", z, [
303
+ e[2] || (e[2] = t("div", { class: "rounded-circle bg-primary bg-opacity-10 p-3 me-3" }, [
304
+ t("i", { class: "bi bi-check-circle-fill text-primary fs-4" })
305
+ ], -1)),
306
+ t("div", null, [
307
+ e[1] || (e[1] = t("h6", { class: "mb-0" }, "Active Vessels", -1)),
308
+ t("h3", Y, d(o.activeVesselsCount), 1)
309
+ ])
310
+ ])
311
+ ])
312
+ ]),
313
+ t("div", K, [
314
+ t("div", W, [
315
+ t("div", G, [
316
+ e[4] || (e[4] = t("div", { class: "rounded-circle bg-secondary bg-opacity-10 p-3 me-3" }, [
317
+ t("i", { class: "bi bi-pause-circle-fill text-secondary fs-4" })
318
+ ], -1)),
319
+ t("div", null, [
320
+ e[3] || (e[3] = t("h6", { class: "mb-0" }, "Inactive", -1)),
321
+ t("h3", J, d(o.inactiveVesselsCount), 1)
322
+ ])
323
+ ])
324
+ ])
325
+ ]),
326
+ o.canAddVessel ? (r(), a("div", X, [
327
+ t("div", {
328
+ class: "card border-0 shadow-sm",
329
+ onClick: e[0] || (e[0] = (...s) => o.handleAddVessel && o.handleAddVessel(...s))
330
+ }, e[5] || (e[5] = [
331
+ t("div", { class: "card-body d-flex align-items-center" }, [
332
+ t("div", { class: "rounded-circle bg-success bg-opacity-10 p-3 me-3" }, [
333
+ t("i", { class: "bi bi-patch-plus-fill text-success fs-4" })
334
+ ]),
335
+ t("div", null, [
336
+ t("h6", { class: "mb-0" }, "Add New Vessel")
337
+ ])
338
+ ], -1)
339
+ ]))
340
+ ])) : u("", !0)
341
+ ]),
342
+ e[11] || (e[11] = t("h4", { class: "mb-4" }, [
343
+ t("i", { class: "bi bi-ship me-2" }),
344
+ b("Registered Vessels")
345
+ ], -1)),
346
+ l.loading ? (r(), a("div", Z, e[6] || (e[6] = [
347
+ t("div", {
348
+ class: "spinner-border text-primary",
349
+ role: "status"
350
+ }, [
351
+ t("span", { class: "visually-hidden" }, "Loading...")
352
+ ], -1),
353
+ t("p", { class: "mt-2" }, "Loading vessels...", -1)
354
+ ]))) : l.vessels.length ? (r(), a("div", te, [
355
+ (r(!0), a(f, null, g(l.vessels, (s) => (r(), a("div", {
356
+ class: "col-lg-6",
357
+ key: s.registrationNumber || s.id
358
+ }, [
359
+ t("div", {
360
+ class: "vessel-card",
361
+ onClick: (m) => o.handleVesselClick(s)
362
+ }, [
363
+ t("div", ie, [
364
+ e[10] || (e[10] = t("div", { class: "vessel-icon left" }, [
365
+ t("i", { class: "fas fa-ship" })
366
+ ], -1)),
367
+ t("div", ne, [
368
+ t("div", le, [
369
+ t("h5", oe, d(s.name), 1),
370
+ t("span", {
371
+ class: h(["vessel-status", o.statusClass(s.status)])
372
+ }, d(s.status), 3)
373
+ ]),
374
+ t("div", re, [
375
+ t("div", ae, [
376
+ e[8] || (e[8] = t("small", { class: "text-muted" }, "Registration #:", -1)),
377
+ t("p", de, d(s.registrationNumber), 1)
378
+ ]),
379
+ t("div", ce, [
380
+ e[9] || (e[9] = t("small", { class: "text-muted" }, "Next Maintenance:", -1)),
381
+ t("p", ue, d(s.nextMaintenance || "Not scheduled"), 1)
382
+ ])
383
+ ])
384
+ ])
385
+ ]),
386
+ t("div", me, [
387
+ t("i", {
388
+ class: "bi bi-trash",
389
+ onClick: C((m) => o.handleDeleteVessel(s), ["stop"])
390
+ }, null, 8, ve)
391
+ ]),
392
+ t("button", {
393
+ class: "btn btn-primary",
394
+ onClick: C((m) => o.handleToggleStatus(s), ["stop"])
395
+ }, d(s.status === "Active" ? "Mark Inactive" : "Mark Active"), 9, he)
396
+ ], 8, se)
397
+ ]))), 128))
398
+ ])) : (r(), a("div", ee, e[7] || (e[7] = [
399
+ t("h4", { class: "alert-heading" }, "Empty Fleet!", -1),
400
+ t("p", null, "You have an empty fleet, you have not added any vessel yet.", -1),
401
+ t("hr", null, null, -1),
402
+ t("p", { class: "mb-0" }, "Click on the add vessel button above, to start adding vessels to your fleet", -1)
403
+ ])))
404
+ ], 64);
405
+ }
406
+ const pe = /* @__PURE__ */ x(q, [["render", fe]]);
407
+ const ge = {
408
+ name: "DashHead",
409
+ props: {
410
+ name: {
411
+ type: String,
412
+ required: !0
413
+ },
414
+ userProfile: {
415
+ type: Object,
416
+ required: !0,
417
+ default: () => ({ role: "viewer", vessel: null })
418
+ }
419
+ },
420
+ emits: [
421
+ "add-user",
422
+ "logged-in"
423
+ ],
424
+ methods: {
425
+ addUser() {
426
+ this.$emit("add-user");
427
+ },
428
+ loggedIn() {
429
+ this.$emit("logged-in");
430
+ }
431
+ }
432
+ }, ye = { class: "page-header d-flex justify-content-between align-items-center" }, be = { style: { "margin-left": "20px" } }, we = { class: "d-flex" };
433
+ function ke(i, e, l, v, n, o) {
434
+ return r(), a("div", ye, [
435
+ t("h2", be, d(l.name), 1),
436
+ t("div", we, [
437
+ this.userProfile.role == "owner" ? (r(), a("button", {
438
+ key: 0,
439
+ class: "btn btn-outline-primary me-2",
440
+ onClick: e[0] || (e[0] = (s) => o.addUser())
441
+ }, e[2] || (e[2] = [
442
+ t("i", { class: "bi bi-bell" }, null, -1),
443
+ t("span", { class: "badge bg-danger" }, "1", -1)
444
+ ]))) : u("", !0),
445
+ t("button", {
446
+ class: "btn btn-outline-primary",
447
+ onClick: e[1] || (e[1] = (s) => o.loggedIn())
448
+ }, e[3] || (e[3] = [
449
+ t("i", { class: "bi bi-person-circle" }, null, -1)
450
+ ]))
451
+ ])
452
+ ]);
453
+ }
454
+ const Ce = /* @__PURE__ */ x(ge, [["render", ke]]);
455
+ const _e = {
456
+ name: "OceanHelmMaintenance",
457
+ props: {
458
+ vesselInfo: {
459
+ type: Object,
460
+ required: !0
461
+ },
462
+ tasks: {
463
+ type: Array,
464
+ default: () => []
465
+ },
466
+ vesselCrew: {
467
+ type: Array,
468
+ default: () => []
469
+ },
470
+ companyInfo: {
471
+ type: Object,
472
+ default: () => ({})
473
+ },
474
+ userProfile: {
475
+ type: Object,
476
+ required: !0
477
+ }
478
+ },
479
+ emits: [
480
+ "dashboard-navigate",
481
+ "load-checklist",
482
+ "save-schedule",
483
+ "update-task",
484
+ "upload-file",
485
+ "delete-evidence",
486
+ "access-denied",
487
+ "show-message",
488
+ "generate-checklist"
489
+ ],
490
+ data() {
491
+ return {
492
+ ready: !0,
493
+ isSaving: !1,
494
+ after: null,
495
+ lastSection: "",
496
+ currentTask: "",
497
+ imgText: "Choose file to upload",
498
+ fileText: "Drag and drop files here or",
499
+ fileattachments: {},
500
+ refreshKey: 0,
501
+ activeSection: "inventory",
502
+ sections: [
503
+ { id: "schedule", name: "Schedule", icon: "📅" },
504
+ { id: "inventory", name: "All Maintenance", icon: "♻️" },
505
+ {
506
+ id: "dashboard",
507
+ name: "Dashboard",
508
+ icon: "☰",
509
+ onClick: () => this.$emit("dashboard-navigate")
510
+ }
511
+ ],
512
+ activeFilter: "all",
513
+ searchQuery: "",
514
+ checklists: [],
515
+ isLoading: !1,
516
+ form: {
517
+ taskName: "",
518
+ description: "",
519
+ maintenanceType: "",
520
+ component: "",
521
+ priority: "",
522
+ dueDate: "",
523
+ estimatedHours: null,
524
+ assignedTo: "",
525
+ recurrence: "",
526
+ lastPerformed: "",
527
+ nextDue: "",
528
+ notifyEmail: !0,
529
+ notifySms: !0,
530
+ reminderDays: "1",
531
+ estimatedDuration: null,
532
+ notes: "",
533
+ status: "Soon",
534
+ email: "",
535
+ remainingDays: null,
536
+ attachments: {}
537
+ },
538
+ maintenanceTasks: [],
539
+ showReport: !1,
540
+ reportDate: (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
541
+ year: "numeric",
542
+ month: "long",
543
+ day: "numeric"
544
+ }),
545
+ reportId: "MT-" + Math.random().toString(36).substr(2, 9).toUpperCase()
546
+ };
547
+ },
548
+ watch: {
549
+ "form.lastPerformed": "calculateNextDue",
550
+ "form.recurrence": "calculateNextDue",
551
+ "form.nextDue": function(i) {
552
+ this.calculateRemainingDays();
553
+ }
554
+ },
555
+ computed: {
556
+ filteredTasks() {
557
+ let i = [...this.tasks];
558
+ if (this.activeFilter === "all" ? i = i.filter((e) => e.status === "Overdue" || e.status === "Soon" || e.status === "Completed") : this.activeFilter === "due" ? i = i.filter((e) => e.status === "Overdue" || e.status === "Soon") : this.activeFilter === "completed" && (i = i.filter((e) => e.status === "Completed")), this.searchQuery) {
559
+ const e = this.searchQuery.toLowerCase();
560
+ i = i.filter(
561
+ (l) => l.component.toLowerCase().includes(e) || l.taskName.toLowerCase().includes(e) || l.assignedTo.toLowerCase().includes(e)
562
+ );
563
+ }
564
+ return i;
565
+ },
566
+ completedCount() {
567
+ return this.checklists.filter((i) => i.completed);
568
+ },
569
+ progress() {
570
+ return Math.round(this.completedCount.length / this.checklists.length * 100);
571
+ },
572
+ checklistButtonLabel() {
573
+ return this.lastSection === "schedule" ? "Approve Maintenance" : "Save Checklist";
574
+ },
575
+ showAddTaskButton() {
576
+ return this.checklistButtonLabel !== "Save Checklist";
577
+ },
578
+ totalEstimatedHours() {
579
+ return this.maintenanceTasks.reduce((i, e) => i + (e.estimatedHours || 0), 0);
580
+ }
581
+ },
582
+ methods: {
583
+ grantAccess(i) {
584
+ const e = this.userProfile;
585
+ return e.role === "owner" || e.role === "staff" || e.role === "captain" && e.vessel === i;
586
+ },
587
+ deepAccess() {
588
+ const i = this.userProfile;
589
+ return i.role === "owner" || i.role === "captain" ? !0 : (this.$emit("access-denied", "You do not have access to do this"), !1);
590
+ },
591
+ deleteTask(i) {
592
+ this.checklists = this.checklists.filter((e) => e.id !== i);
593
+ },
594
+ addTask(i) {
595
+ i && i.preventDefault(), this.$emit("show-message", {
596
+ type: "prompt",
597
+ title: "Add New Task",
598
+ message: "Enter the task details",
599
+ callback: (e) => {
600
+ if (e) {
601
+ const l = {
602
+ id: Date.now(),
603
+ text: e,
604
+ completed: !1
605
+ };
606
+ this.checklists.push(l);
607
+ }
608
+ }
609
+ });
610
+ },
611
+ setFilter(i) {
612
+ this.activeFilter = i;
613
+ },
614
+ loadChecklist(i) {
615
+ this.isLoading = !0, this.$emit("generate-checklist", {
616
+ component: i,
617
+ callback: (e) => {
618
+ this.checklists = e.map((l) => ({
619
+ ...l,
620
+ completed: !1
621
+ })), this.isLoading = !1;
622
+ }
623
+ });
624
+ },
625
+ showMaintenance(i) {
626
+ if (this.deepAccess()) {
627
+ const e = this.tasks.find((l) => l.component === i);
628
+ e && e.checklistProgress ? this.checklists = [...e.checklistProgress] : this.loadChecklist(i), this.after = e == null ? void 0 : e.after, this.currentTask = i, this.lastSection = "inventory", this.activeSection = "maintenance";
629
+ }
630
+ },
631
+ printMaintenance(i) {
632
+ const e = this.tasks.find((l) => l.component === i);
633
+ this.maintenanceTasks = [e], this.loadMaintenanceData(), this.showReport = !0, this.$nextTick(() => {
634
+ setTimeout(() => {
635
+ window.print(), this.showReport = !1;
636
+ }, 100);
637
+ });
638
+ },
639
+ switchSchedule() {
640
+ this.deepAccess() && (this.activeSection = "schedule");
641
+ },
642
+ handleFiles(i) {
643
+ this.imgText = i.target.files[0].name, this.form.attachments = {
644
+ file: i.target.files[0]
645
+ };
646
+ },
647
+ handleImg(i) {
648
+ this.fileText = i.target.files[0].name, this.fileattachments = {
649
+ file: i.target.files[0]
650
+ };
651
+ },
652
+ validateForm() {
653
+ const i = [
654
+ "taskName",
655
+ "description",
656
+ "maintenanceType",
657
+ "component",
658
+ "priority",
659
+ "estimatedHours",
660
+ "recurrence",
661
+ "lastPerformed",
662
+ "assignedTo"
663
+ ];
664
+ for (const e of i)
665
+ if (!this.form[e])
666
+ return this.$emit("show-message", {
667
+ type: "error",
668
+ title: "Missing info",
669
+ message: `Please fill in the required field: ${e}`
670
+ }), !1;
671
+ return !0;
672
+ },
673
+ handleSectionClick(i) {
674
+ this.activeSection = i.id, typeof i.onClick == "function" && i.onClick();
675
+ },
676
+ calculateNextDue() {
677
+ const i = this.form.lastPerformed ? new Date(this.form.lastPerformed) : null, e = this.form.recurrence;
678
+ if (!i || !e)
679
+ return;
680
+ let l = new Date(i);
681
+ switch (e) {
682
+ case "daily":
683
+ l.setDate(l.getDate() + 1);
684
+ break;
685
+ case "weekly":
686
+ l.setDate(l.getDate() + 7);
687
+ break;
688
+ case "monthly":
689
+ l.setMonth(l.getMonth() + 1);
690
+ break;
691
+ case "quarterly":
692
+ l.setMonth(l.getMonth() + 3);
693
+ break;
694
+ case "semi-annual":
695
+ l.setMonth(l.getMonth() + 6);
696
+ break;
697
+ case "annual":
698
+ l.setFullYear(l.getFullYear() + 1);
699
+ break;
700
+ case "once":
701
+ case "custom":
702
+ return;
703
+ }
704
+ this.form.nextDue = l.toISOString().split("T")[0];
705
+ },
706
+ calculateRemainingDays() {
707
+ if (!this.form.nextDue) {
708
+ this.form.remainingDays = null;
709
+ return;
710
+ }
711
+ const i = /* @__PURE__ */ new Date(), e = new Date(this.form.nextDue);
712
+ i.setHours(0, 0, 0, 0), e.setHours(0, 0, 0, 0);
713
+ const l = e - i, v = Math.ceil(l / (1e3 * 60 * 60 * 24));
714
+ this.form.remainingDays = `${v} Days`;
715
+ },
716
+ async saveSchedule() {
717
+ if (this.isSaving = !0, !this.validateForm()) {
718
+ this.isSaving = !1;
719
+ return;
720
+ }
721
+ const i = { ...this.form };
722
+ if (this.form.component === "Other" && this.form.customComponent && (i.component = this.form.customComponent), i.email = this.companyInfo.email, this.tasks.some((l) => l.component === i.component)) {
723
+ this.$emit("show-message", {
724
+ type: "error",
725
+ title: "Duplicate Component",
726
+ message: `A task with the component "${i.component}" already exists in maintenance`
727
+ }), this.isSaving = !1;
728
+ return;
729
+ }
730
+ delete i.customComponent, this.$emit("save-schedule", {
731
+ taskData: i,
732
+ file: i.attachments.file,
733
+ callback: (l) => {
734
+ this.isSaving = !1, l && (this.loadChecklist(i.component), this.lastSection = "schedule", this.currentTask = i.component, this.resetForm(), this.activeSection = "maintenance");
735
+ }
736
+ });
737
+ },
738
+ resetForm() {
739
+ this.form = {
740
+ taskName: "",
741
+ description: "",
742
+ maintenanceType: "",
743
+ component: "",
744
+ priority: "",
745
+ dueDate: "",
746
+ estimatedHours: null,
747
+ assignedTo: "",
748
+ recurrence: "",
749
+ lastPerformed: "",
750
+ nextDue: "",
751
+ notifyEmail: !0,
752
+ notifySms: !0,
753
+ reminderDays: "1",
754
+ estimatedDuration: null,
755
+ notes: "",
756
+ status: "Soon",
757
+ remainingDays: null,
758
+ attachments: {}
759
+ };
760
+ },
761
+ toggleTask(i) {
762
+ i.completed = !i.completed;
763
+ },
764
+ async resetTasks() {
765
+ const e = this.checklists.every((v) => v.completed) ? "Completed" : "In Progress", l = {
766
+ checklistProgress: [...this.checklists],
767
+ status: e,
768
+ component: this.currentTask,
769
+ after: this.after
770
+ };
771
+ this.$emit("update-task", {
772
+ updateData: l,
773
+ file: this.fileattachments.file,
774
+ callback: (v, n) => {
775
+ v && (n && (this.after = n), this.fileattachments = {}, this.fileText = "Drag and drop files here or", this.refreshKey += 1, this.activeSection = "inventory");
776
+ }
777
+ });
778
+ },
779
+ loadMaintenanceData() {
780
+ this.reportId = "MT-" + Math.random().toString(36).substr(2, 9).toUpperCase(), this.reportDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
781
+ year: "numeric",
782
+ month: "long",
783
+ day: "numeric"
784
+ });
785
+ },
786
+ formatDate(i) {
787
+ return i ? new Date(i).toLocaleDateString("en-US", {
788
+ year: "numeric",
789
+ month: "short",
790
+ day: "numeric"
791
+ }) : "N/A";
792
+ },
793
+ getTaskStatusClass(i) {
794
+ return i.status === "Completed" ? "completed" : i.status === "Overdue" ? "overdue" : i.status === "In Progress" ? "in-progress" : "pending";
795
+ },
796
+ getChecklistProgress(i) {
797
+ if (!i.checklistProgress || i.checklistProgress.length === 0)
798
+ return 0;
799
+ const e = i.checklistProgress.filter((l) => l.completed).length;
800
+ return Math.round(e / i.checklistProgress.length * 100);
801
+ },
802
+ getCompletedChecklistItems(i) {
803
+ return i.checklistProgress ? i.checklistProgress.filter((e) => e.completed).length : 0;
804
+ },
805
+ generateRecommendations() {
806
+ return [
807
+ "Maintain regular communication with assigned technicians",
808
+ "Ensure all safety protocols are followed during maintenance activities",
809
+ "Update task progress and notes in real-time for accurate reporting"
810
+ ];
811
+ },
812
+ deleteEvidence() {
813
+ this.$emit("delete-evidence", {
814
+ currentTask: this.currentTask,
815
+ callback: (i) => {
816
+ i && (this.after = null, this.fileText = "Drag and drop files here or", this.fileattachments = {}, this.refreshKey += 1);
817
+ }
818
+ });
819
+ }
820
+ }
821
+ }, xe = { key: 0 }, Se = ["onClick"], De = { class: "content" }, Ae = {
822
+ key: 0,
823
+ class: "loading-container"
824
+ }, Te = { key: 1 }, Pe = { class: "container" }, Me = { class: "d-flex justify-content-between align-items-center" }, Ee = { class: "progress-container" }, Ve = { class: "progress-info" }, Ne = { class: "progress-bar" }, Le = { class: "checklist" }, Fe = ["onClick"], Ue = { key: 0 }, Ie = ["onClick"], Re = ["onClick"], Oe = { key: 0 }, Be = { class: "checklist" }, He = { class: "checklist-item" }, qe = { class: "attachment-area" }, je = {
825
+ key: 2,
826
+ class: "status"
827
+ }, $e = { class: "form-group" }, Qe = { class: "form-group" }, ze = { class: "input-group" }, Ye = { class: "form-group" }, Ke = { class: "form-group" }, We = { class: "input-group" }, Ge = { class: "form-group" }, Je = { class: "form-group" }, Xe = { class: "input-group" }, Ze = { class: "form-group" }, et = { class: "form-group" }, tt = ["value"], st = { class: "input-group" }, it = { class: "form-group" }, nt = { class: "input-group" }, lt = { class: "form-group" }, ot = { class: "form-group" }, rt = { class: "form-group" }, at = { class: "checkbox-group" }, dt = { class: "checkbox-item" }, ct = { class: "checkbox-item" }, ut = { class: "input-group" }, mt = { class: "form-group" }, vt = { class: "form-group" }, ht = { class: "form-group" }, ft = { class: "attachment-area" }, pt = { class: "action-buttons" }, gt = ["disabled"], yt = { class: "task-table-wrapper" }, bt = { class: "table-controls" }, wt = { class: "filters" }, kt = { class: "task-table" }, Ct = ["onClick"], _t = ["onClick"], xt = { key: 0 }, St = {
828
+ class: "alert alert-primary",
829
+ role: "alert"
830
+ }, Dt = { class: "mb-0" }, At = {
831
+ class: "report-container",
832
+ ref: "reportContainer"
833
+ }, Tt = { class: "report-info" }, Pt = { class: "info-box" }, Mt = { class: "info-box" }, Et = { class: "info-box" }, Vt = { class: "section" }, Nt = { class: "summary-grid" }, Lt = { class: "summary-card" }, Ft = { class: "summary-number" }, Ut = { class: "section" }, It = { class: "task-header" }, Rt = { class: "task-title" }, Ot = { class: "task-component" }, Bt = { class: "task-details" }, Ht = { class: "detail-item" }, qt = { class: "detail-value" }, jt = { class: "detail-item" }, $t = { class: "detail-value" }, Qt = { class: "detail-item" }, zt = { class: "detail-value" }, Yt = { class: "detail-item" }, Kt = { class: "detail-value" }, Wt = { class: "detail-item" }, Gt = { class: "detail-value" }, Jt = { class: "detail-item" }, Xt = { class: "detail-value" }, Zt = {
834
+ key: 0,
835
+ style: { margin: "15px 0", padding: "10px", background: "white", "border-radius": "5px" }
836
+ }, es = { class: "detail-value" }, ts = {
837
+ key: 1,
838
+ style: { margin: "15px 0", padding: "10px", background: "white", "border-radius": "5px" }
839
+ }, ss = { class: "detail-value" }, is = {
840
+ key: 2,
841
+ class: "checklist-progress"
842
+ }, ns = { class: "progress-bar" }, ls = { style: { "font-size": "0.9em", color: "#666", "margin-top": "5px" } }, os = { class: "checklist-items" }, rs = { class: "checklist-icon" }, as = { class: "section" }, ds = { class: "info-box" }, cs = { class: "signature-section" }, us = { class: "signature-box" }, ms = { style: { "margin-top": "10px", color: "#666" } };
843
+ function vs(i, e, l, v, n, o) {
844
+ return n.ready ? (r(), a("div", xe, [
845
+ t("div", null, [
846
+ c(t("nav", null, [
847
+ (r(!0), a(f, null, g(n.sections, (s) => (r(), a("button", {
848
+ key: s.id,
849
+ class: h(["nav-btn", { active: n.activeSection === s.id }]),
850
+ onClick: (m) => o.handleSectionClick(s)
851
+ }, d(s.icon) + " " + d(s.name), 11, Se))), 128))
852
+ ], 512), [
853
+ [_, !n.showReport]
854
+ ]),
855
+ c(t("div", De, [
856
+ c(t("section", {
857
+ class: h(["form-section", { active: n.activeSection === "maintenance" }])
858
+ }, [
859
+ e[37] || (e[37] = t("h2", null, "🛠️ Maintenance Tasks", -1)),
860
+ n.isLoading ? (r(), a("div", Ae, e[27] || (e[27] = [
861
+ t("div", { class: "loading-spinner" }, null, -1),
862
+ t("p", null, "Loading checklist...", -1)
863
+ ]))) : u("", !0),
864
+ n.isLoading ? u("", !0) : (r(), a("form", Te, [
865
+ t("div", Pe, [
866
+ t("div", Me, [
867
+ e[29] || (e[29] = t("h1", null, "Maintenance Checklist", -1)),
868
+ o.showAddTaskButton ? (r(), a("button", {
869
+ key: 0,
870
+ class: "btn btn-outline-custom",
871
+ onClick: e[0] || (e[0] = C((s) => o.addTask(), ["prevent"]))
872
+ }, e[28] || (e[28] = [
873
+ b(" Manually Add Task ", -1),
874
+ t("i", { class: "fas fa-plus" }, null, -1)
875
+ ]))) : u("", !0)
876
+ ]),
877
+ t("div", Ee, [
878
+ t("div", Ve, " Progress: " + d(o.progress) + "% (" + d(o.completedCount.length) + "/" + d(n.checklists.length) + ") ", 1),
879
+ t("div", Ne, [
880
+ t("div", {
881
+ class: "progress-fill",
882
+ style: S({ width: o.progress + "%" })
883
+ }, null, 4)
884
+ ])
885
+ ]),
886
+ t("ul", Le, [
887
+ (r(!0), a(f, null, g(n.checklists, (s) => (r(), a("li", {
888
+ key: s.id,
889
+ class: "checklist-item"
890
+ }, [
891
+ t("div", {
892
+ class: h(["checkbox", { checked: s.completed }]),
893
+ onClick: (m) => o.toggleTask(s)
894
+ }, [
895
+ s.completed ? (r(), a("span", Ue, "✓")) : u("", !0)
896
+ ], 10, Fe),
897
+ t("span", {
898
+ class: h(["task-text", { completed: s.completed }]),
899
+ onClick: (m) => o.toggleTask(s)
900
+ }, d(s.text), 11, Ie),
901
+ o.showAddTaskButton ? (r(), a("button", {
902
+ key: 0,
903
+ class: "delete-btn",
904
+ onClick: (m) => o.deleteTask(s.id),
905
+ title: "Delete task"
906
+ }, e[30] || (e[30] = [
907
+ k('<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3,6 5,6 21,6"></polyline><path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>', 1)
908
+ ]), 8, Re)) : u("", !0)
909
+ ]))), 128))
910
+ ]),
911
+ n.after ? (r(), a("div", Oe, [
912
+ e[33] || (e[33] = t("label", null, "Upload Image Evidence", -1)),
913
+ t("ul", Be, [
914
+ t("li", He, [
915
+ e[32] || (e[32] = t("span", { class: "task-text" }, " Image Evidence Already Uploaded ", -1)),
916
+ t("button", {
917
+ type: "button",
918
+ class: "delete-btn",
919
+ onClick: e[1] || (e[1] = (s) => o.deleteEvidence()),
920
+ title: "Delete Image"
921
+ }, e[31] || (e[31] = [
922
+ k('<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3,6 5,6 21,6"></polyline><path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>', 1)
923
+ ]))
924
+ ])
925
+ ])
926
+ ])) : (r(), a("div", {
927
+ class: "form-group",
928
+ key: n.refreshKey || "default"
929
+ }, [
930
+ e[35] || (e[35] = t("label", null, "Upload Image Evidence", -1)),
931
+ e[36] || (e[36] = t("p", null, "You can only upload one image evidence here.", -1)),
932
+ t("div", qe, [
933
+ t("p", null, d(n.fileText), 1),
934
+ t("input", {
935
+ type: "file",
936
+ id: "evidence-files",
937
+ class: "file-input",
938
+ onChange: e[2] || (e[2] = (...s) => o.handleImg && o.handleImg(...s))
939
+ }, null, 32),
940
+ e[34] || (e[34] = t("label", {
941
+ for: "evidence-files",
942
+ class: "file-label"
943
+ }, "Browse Files", -1))
944
+ ])
945
+ ])),
946
+ o.completedCount === n.checklists.length ? (r(), a("div", je, " All tasks completed! ✅ ")) : u("", !0),
947
+ t("button", {
948
+ class: "reset-button",
949
+ onClick: e[3] || (e[3] = C((...s) => o.resetTasks && o.resetTasks(...s), ["prevent"]))
950
+ }, d(o.checklistButtonLabel), 1)
951
+ ])
952
+ ]))
953
+ ], 2), [
954
+ [_, n.activeSection === "maintenance"]
955
+ ]),
956
+ c(t("section", {
957
+ class: h(["form-section", { active: n.activeSection === "schedule" }])
958
+ }, [
959
+ e[62] || (e[62] = t("h2", null, "📅 Maintenance Schedule", -1)),
960
+ t("form", null, [
961
+ t("div", $e, [
962
+ e[38] || (e[38] = t("label", { for: "task-name" }, "Task Name", -1)),
963
+ c(t("input", {
964
+ type: "text",
965
+ id: "task-name",
966
+ "onUpdate:modelValue": e[4] || (e[4] = (s) => n.form.taskName = s),
967
+ required: ""
968
+ }, null, 512), [
969
+ [y, n.form.taskName]
970
+ ])
971
+ ]),
972
+ t("div", Qe, [
973
+ e[39] || (e[39] = t("label", { for: "task-description" }, "Description", -1)),
974
+ c(t("textarea", {
975
+ id: "task-description",
976
+ "onUpdate:modelValue": e[5] || (e[5] = (s) => n.form.description = s),
977
+ required: ""
978
+ }, null, 512), [
979
+ [y, n.form.description]
980
+ ])
981
+ ]),
982
+ t("div", ze, [
983
+ t("div", Ye, [
984
+ e[41] || (e[41] = t("label", { for: "maintenance-type" }, "Maintenance Type", -1)),
985
+ c(t("select", {
986
+ id: "maintenance-type",
987
+ "onUpdate:modelValue": e[6] || (e[6] = (s) => n.form.maintenanceType = s),
988
+ required: ""
989
+ }, e[40] || (e[40] = [
990
+ k('<option value="">-- Select Type --</option><option value="preventive">Preventive</option><option value="corrective">Corrective</option><option value="predictive">Predictive</option><option value="condition">Condition-Based</option>', 5)
991
+ ]), 512), [
992
+ [w, n.form.maintenanceType]
993
+ ])
994
+ ]),
995
+ t("div", Ke, [
996
+ e[43] || (e[43] = t("label", { for: "component" }, "Component/System", -1)),
997
+ c(t("select", {
998
+ id: "component",
999
+ "onUpdate:modelValue": e[7] || (e[7] = (s) => n.form.component = s),
1000
+ required: ""
1001
+ }, e[42] || (e[42] = [
1002
+ k('<option value="">-- Select Component --</option><option value="engine">Engine</option><option value="hull">Hull</option><option value="electronics">Electronics</option><option value="deck">Deck Machinery</option><option value="plumbing">Plumbing</option><option value="electrical">Electrical</option><option value="hvac">HVAC</option><option value="safety">Safety Systems</option><option value="Other">Other</option>', 10)
1003
+ ]), 512), [
1004
+ [w, n.form.component]
1005
+ ]),
1006
+ n.form.component === "Other" ? c((r(), a("input", {
1007
+ key: 0,
1008
+ type: "text",
1009
+ placeholder: "Enter custom component/system",
1010
+ "onUpdate:modelValue": e[8] || (e[8] = (s) => n.form.customComponent = s),
1011
+ style: { "margin-top": "8px" }
1012
+ }, null, 512)), [
1013
+ [y, n.form.customComponent]
1014
+ ]) : u("", !0)
1015
+ ])
1016
+ ]),
1017
+ t("div", We, [
1018
+ t("div", Ge, [
1019
+ e[45] || (e[45] = t("label", { for: "priority" }, "Priority", -1)),
1020
+ c(t("select", {
1021
+ id: "priority",
1022
+ "onUpdate:modelValue": e[9] || (e[9] = (s) => n.form.priority = s),
1023
+ required: ""
1024
+ }, e[44] || (e[44] = [
1025
+ t("option", { value: "low" }, "Low", -1),
1026
+ t("option", { value: "medium" }, "Medium", -1),
1027
+ t("option", { value: "high" }, "High", -1),
1028
+ t("option", { value: "critical" }, "Critical", -1)
1029
+ ]), 512), [
1030
+ [w, n.form.priority]
1031
+ ])
1032
+ ]),
1033
+ t("div", Je, [
1034
+ e[46] || (e[46] = t("label", { for: "status" }, "Status", -1)),
1035
+ c(t("input", {
1036
+ type: "text",
1037
+ id: "status",
1038
+ "onUpdate:modelValue": e[10] || (e[10] = (s) => n.form.status = s),
1039
+ readonly: ""
1040
+ }, null, 512), [
1041
+ [y, n.form.status]
1042
+ ])
1043
+ ])
1044
+ ]),
1045
+ t("div", Xe, [
1046
+ t("div", Ze, [
1047
+ e[47] || (e[47] = t("label", { for: "estimated-hours" }, "Estimated Hours", -1)),
1048
+ c(t("input", {
1049
+ type: "number",
1050
+ id: "estimated-hours",
1051
+ "onUpdate:modelValue": e[11] || (e[11] = (s) => n.form.estimatedHours = s),
1052
+ min: "0",
1053
+ step: "0.5"
1054
+ }, null, 512), [
1055
+ [y, n.form.estimatedHours]
1056
+ ])
1057
+ ])
1058
+ ]),
1059
+ t("div", et, [
1060
+ e[49] || (e[49] = t("label", { for: "assigned-to" }, "Assigned To", -1)),
1061
+ c(t("select", {
1062
+ id: "assigned-to",
1063
+ "onUpdate:modelValue": e[12] || (e[12] = (s) => n.form.assignedTo = s)
1064
+ }, [
1065
+ e[48] || (e[48] = t("option", { value: "" }, "-- Select Personnel --", -1)),
1066
+ (r(!0), a(f, null, g(l.vesselCrew, (s) => (r(), a("option", {
1067
+ key: s.id,
1068
+ value: `${s.name} - ${s.role}`
1069
+ }, d(s.name) + " - " + d(s.role), 9, tt))), 128))
1070
+ ], 512), [
1071
+ [w, n.form.assignedTo]
1072
+ ])
1073
+ ]),
1074
+ t("div", st, [
1075
+ t("div", it, [
1076
+ e[51] || (e[51] = t("label", { for: "recurrence-type" }, "Recurrence", -1)),
1077
+ c(t("select", {
1078
+ id: "recurrence-type",
1079
+ "onUpdate:modelValue": e[13] || (e[13] = (s) => n.form.recurrence = s),
1080
+ required: ""
1081
+ }, e[50] || (e[50] = [
1082
+ k('<option value="once">One-time</option><option value="daily">Daily</option><option value="weekly">Weekly</option><option value="monthly">Monthly</option><option value="quarterly">Quarterly</option><option value="semi-annual">Semi-annually</option><option value="annual">Annually</option><option value="custom">Custom Interval</option>', 8)
1083
+ ]), 512), [
1084
+ [w, n.form.recurrence]
1085
+ ])
1086
+ ])
1087
+ ]),
1088
+ t("div", nt, [
1089
+ t("div", lt, [
1090
+ e[52] || (e[52] = t("label", { for: "last-performed" }, "Last Performed Date", -1)),
1091
+ c(t("input", {
1092
+ type: "date",
1093
+ id: "last-performed",
1094
+ "onUpdate:modelValue": e[14] || (e[14] = (s) => n.form.lastPerformed = s)
1095
+ }, null, 512), [
1096
+ [y, n.form.lastPerformed]
1097
+ ])
1098
+ ]),
1099
+ t("div", ot, [
1100
+ e[53] || (e[53] = t("label", { for: "next-due" }, "Due Date", -1)),
1101
+ c(t("input", {
1102
+ type: "date",
1103
+ id: "next-due",
1104
+ "onUpdate:modelValue": e[15] || (e[15] = (s) => n.form.nextDue = s),
1105
+ required: ""
1106
+ }, null, 512), [
1107
+ [y, n.form.nextDue]
1108
+ ])
1109
+ ])
1110
+ ]),
1111
+ t("div", rt, [
1112
+ e[56] || (e[56] = t("label", null, "Notifications", -1)),
1113
+ t("div", at, [
1114
+ t("div", dt, [
1115
+ c(t("input", {
1116
+ type: "checkbox",
1117
+ id: "notify-email",
1118
+ "onUpdate:modelValue": e[16] || (e[16] = (s) => n.form.notifyEmail = s)
1119
+ }, null, 512), [
1120
+ [D, n.form.notifyEmail]
1121
+ ]),
1122
+ e[54] || (e[54] = t("label", { for: "notify-email" }, "Email Notification", -1))
1123
+ ]),
1124
+ t("div", ct, [
1125
+ c(t("input", {
1126
+ type: "checkbox",
1127
+ id: "notify-sms",
1128
+ "onUpdate:modelValue": e[17] || (e[17] = (s) => n.form.notifySms = s)
1129
+ }, null, 512), [
1130
+ [D, n.form.notifySms]
1131
+ ]),
1132
+ e[55] || (e[55] = t("label", { for: "notify-sms" }, "SMS Notification", -1))
1133
+ ])
1134
+ ])
1135
+ ]),
1136
+ t("div", ut, [
1137
+ t("div", mt, [
1138
+ e[58] || (e[58] = t("label", { for: "reminder-days" }, "Reminder (Days Before)", -1)),
1139
+ c(t("select", {
1140
+ id: "reminder-days",
1141
+ "onUpdate:modelValue": e[18] || (e[18] = (s) => n.form.reminderDays = s)
1142
+ }, e[57] || (e[57] = [
1143
+ k('<option value="1">1 day</option><option value="3">3 days</option><option value="7">1 week</option><option value="14">2 weeks</option><option value="30">1 month</option>', 5)
1144
+ ]), 512), [
1145
+ [w, n.form.reminderDays]
1146
+ ])
1147
+ ])
1148
+ ]),
1149
+ t("div", vt, [
1150
+ e[59] || (e[59] = t("label", { for: "schedule-notes" }, "Notes", -1)),
1151
+ c(t("textarea", {
1152
+ id: "schedule-notes",
1153
+ "onUpdate:modelValue": e[19] || (e[19] = (s) => n.form.notes = s)
1154
+ }, null, 512), [
1155
+ [y, n.form.notes]
1156
+ ])
1157
+ ]),
1158
+ t("div", ht, [
1159
+ e[61] || (e[61] = t("label", null, "Attachments", -1)),
1160
+ t("div", ft, [
1161
+ t("p", null, d(n.imgText), 1),
1162
+ t("input", {
1163
+ type: "file",
1164
+ id: "maintenance-files",
1165
+ class: "file-input",
1166
+ onChange: e[20] || (e[20] = (...s) => o.handleFiles && o.handleFiles(...s)),
1167
+ multiple: ""
1168
+ }, null, 32),
1169
+ e[60] || (e[60] = t("label", {
1170
+ for: "maintenance-files",
1171
+ class: "file-label"
1172
+ }, "Browse Files", -1))
1173
+ ])
1174
+ ]),
1175
+ t("div", pt, [
1176
+ t("button", {
1177
+ type: "button",
1178
+ class: "btn btn-primary",
1179
+ onClick: e[21] || (e[21] = C((...s) => o.saveSchedule && o.saveSchedule(...s), ["prevent"])),
1180
+ disabled: n.isSaving
1181
+ }, d(n.isSaving ? "Saving..." : "Save Schedule"), 9, gt)
1182
+ ])
1183
+ ])
1184
+ ], 2), [
1185
+ [_, n.activeSection === "schedule"]
1186
+ ]),
1187
+ c(t("section", {
1188
+ class: h(["form-section", { active: n.activeSection === "inventory" }])
1189
+ }, [
1190
+ e[68] || (e[68] = t("h2", null, "All Maintenance", -1)),
1191
+ t("div", yt, [
1192
+ t("div", bt, [
1193
+ t("div", wt, [
1194
+ t("button", {
1195
+ class: h({ active: n.activeFilter === "due" }),
1196
+ onClick: e[22] || (e[22] = (s) => o.setFilter("due"))
1197
+ }, "Due", 2),
1198
+ t("button", {
1199
+ class: h({ active: n.activeFilter === "all" }),
1200
+ onClick: e[23] || (e[23] = (s) => o.setFilter("all"))
1201
+ }, "All", 2),
1202
+ t("button", {
1203
+ class: h({ active: n.activeFilter === "completed" }),
1204
+ onClick: e[24] || (e[24] = (s) => o.setFilter("completed"))
1205
+ }, "Completed", 2),
1206
+ c(t("input", {
1207
+ type: "text",
1208
+ "onUpdate:modelValue": e[25] || (e[25] = (s) => n.searchQuery = s),
1209
+ placeholder: "Search..."
1210
+ }, null, 512), [
1211
+ [y, n.searchQuery]
1212
+ ])
1213
+ ])
1214
+ ]),
1215
+ t("table", kt, [
1216
+ e[63] || (e[63] = t("thead", null, [
1217
+ t("tr", null, [
1218
+ t("th", null, "Equipment"),
1219
+ t("th", null, "Task Name"),
1220
+ t("th", null, "Assigned To"),
1221
+ t("th", null, "Intervals"),
1222
+ t("th", null, "Remaining"),
1223
+ t("th", null, "Next Due"),
1224
+ t("th", null, "Status"),
1225
+ t("th", null, "Action")
1226
+ ])
1227
+ ], -1)),
1228
+ t("tbody", null, [
1229
+ (r(!0), a(f, null, g(o.filteredTasks, (s) => (r(), a("tr", {
1230
+ key: s.id
1231
+ }, [
1232
+ t("td", null, d(s.component), 1),
1233
+ t("td", null, d(s.taskName), 1),
1234
+ t("td", null, d(s.assignedTo), 1),
1235
+ t("td", null, d(s.recurrence), 1),
1236
+ t("td", null, d(s.remainingDays), 1),
1237
+ t("td", null, d(s.nextDue), 1),
1238
+ t("td", null, [
1239
+ t("span", {
1240
+ class: h(["status-badge", s.status.toLowerCase().replace(" ", "-")])
1241
+ }, d(s.status), 3)
1242
+ ]),
1243
+ t("td", null, [
1244
+ s.status === "Completed" ? (r(), a("button", {
1245
+ key: 0,
1246
+ onClick: (m) => o.printMaintenance(s.component),
1247
+ class: "status-action"
1248
+ }, "Print", 8, Ct)) : (r(), a("button", {
1249
+ key: 1,
1250
+ onClick: (m) => o.showMaintenance(s.component),
1251
+ class: "status-action"
1252
+ }, "Start", 8, _t))
1253
+ ])
1254
+ ]))), 128))
1255
+ ])
1256
+ ]),
1257
+ l.tasks.length ? u("", !0) : (r(), a("div", xt, [
1258
+ t("div", St, [
1259
+ e[65] || (e[65] = t("h4", { class: "alert-heading" }, "Such Empty!!!", -1)),
1260
+ e[66] || (e[66] = t("p", null, "You have no maintenance, because you have not scheduled any for this ship.", -1)),
1261
+ e[67] || (e[67] = t("hr", null, null, -1)),
1262
+ t("p", Dt, [
1263
+ e[64] || (e[64] = b("Navigate to the schedule tab, to start scheduling. Or click on this button to ", -1)),
1264
+ t("button", {
1265
+ type: "button",
1266
+ class: "btn btn-primary",
1267
+ onClick: e[26] || (e[26] = (s) => o.switchSchedule())
1268
+ }, "Schedule")
1269
+ ])
1270
+ ])
1271
+ ]))
1272
+ ])
1273
+ ], 2), [
1274
+ [_, n.activeSection === "inventory"]
1275
+ ])
1276
+ ], 512), [
1277
+ [_, !n.showReport]
1278
+ ]),
1279
+ c(t("div", At, [
1280
+ e[89] || (e[89] = t("div", { class: "header" }, [
1281
+ t("div", { class: "report-title" }, "MAINTENANCE TASK REPORT")
1282
+ ], -1)),
1283
+ t("div", Tt, [
1284
+ t("div", Pt, [
1285
+ e[69] || (e[69] = t("div", { class: "info-label" }, "Report Generated:", -1)),
1286
+ t("div", null, d(n.reportDate), 1)
1287
+ ]),
1288
+ t("div", Mt, [
1289
+ e[70] || (e[70] = t("div", { class: "info-label" }, "Report ID:", -1)),
1290
+ t("div", null, d(n.reportId), 1)
1291
+ ]),
1292
+ t("div", Et, [
1293
+ e[71] || (e[71] = t("div", { class: "info-label" }, "Total Tasks:", -1)),
1294
+ t("div", null, d(n.maintenanceTasks.length), 1)
1295
+ ]),
1296
+ e[72] || (e[72] = t("div", { class: "info-box" }, [
1297
+ t("div", { class: "info-label" }, "Generated By:"),
1298
+ t("div", null, "OceanHelm System")
1299
+ ], -1))
1300
+ ]),
1301
+ t("div", Vt, [
1302
+ e[75] || (e[75] = t("div", { class: "section-title" }, "📊 Task Summary", -1)),
1303
+ t("div", Nt, [
1304
+ e[74] || (e[74] = k('<div class="summary-card"><div class="summary-number">1</div><div class="summary-label">Completed</div></div><div class="summary-card"><div class="summary-number">0</div><div class="summary-label">Pending</div></div><div class="summary-card"><div class="summary-number">0</div><div class="summary-label">Overdue</div></div>', 3)),
1305
+ t("div", Lt, [
1306
+ t("div", Ft, d(o.totalEstimatedHours), 1),
1307
+ e[73] || (e[73] = t("div", { class: "summary-label" }, "Total Hours", -1))
1308
+ ])
1309
+ ])
1310
+ ]),
1311
+ t("div", Ut, [
1312
+ e[85] || (e[85] = t("div", { class: "section-title" }, "🔧 Maintenance Tasks", -1)),
1313
+ (r(!0), a(f, null, g(n.maintenanceTasks, (s) => (r(), a("div", {
1314
+ key: s.taskName,
1315
+ class: h(["task-item", o.getTaskStatusClass(s)])
1316
+ }, [
1317
+ t("div", It, [
1318
+ t("div", null, [
1319
+ t("div", Rt, [
1320
+ b(d(s.taskName) + " ", 1),
1321
+ t("span", {
1322
+ class: h(["maintenance-type", "type-" + s.maintenanceType])
1323
+ }, d(s.maintenanceType), 3)
1324
+ ]),
1325
+ t("div", Ot, "Component: " + d(s.component), 1)
1326
+ ]),
1327
+ t("span", {
1328
+ class: h(["status-badge", "status-" + s.status.toLowerCase().replace(" ", "-")])
1329
+ }, d(s.status), 3)
1330
+ ]),
1331
+ t("div", Bt, [
1332
+ t("div", Ht, [
1333
+ e[76] || (e[76] = t("div", { class: "detail-label" }, "Assigned To", -1)),
1334
+ t("div", qt, d(s.assignedTo), 1)
1335
+ ]),
1336
+ t("div", jt, [
1337
+ e[77] || (e[77] = t("div", { class: "detail-label" }, "Estimated Hours", -1)),
1338
+ t("div", $t, d(s.estimatedHours) + " hours", 1)
1339
+ ]),
1340
+ t("div", Qt, [
1341
+ e[78] || (e[78] = t("div", { class: "detail-label" }, "Last Performed", -1)),
1342
+ t("div", zt, d(o.formatDate(s.lastPerformed)), 1)
1343
+ ]),
1344
+ t("div", Yt, [
1345
+ e[79] || (e[79] = t("div", { class: "detail-label" }, "Next Due", -1)),
1346
+ t("div", Kt, d(o.formatDate(s.nextDue)), 1)
1347
+ ]),
1348
+ t("div", Wt, [
1349
+ e[80] || (e[80] = t("div", { class: "detail-label" }, "Recurrence", -1)),
1350
+ t("div", Gt, d(s.recurrence), 1)
1351
+ ]),
1352
+ t("div", Jt, [
1353
+ e[81] || (e[81] = t("div", { class: "detail-label" }, "Remaining Days", -1)),
1354
+ t("div", Xt, d(s.remainingDays) + " days", 1)
1355
+ ])
1356
+ ]),
1357
+ s.description ? (r(), a("div", Zt, [
1358
+ e[82] || (e[82] = t("div", { class: "detail-label" }, "Description", -1)),
1359
+ t("div", es, d(s.description), 1)
1360
+ ])) : u("", !0),
1361
+ s.notes ? (r(), a("div", ts, [
1362
+ e[83] || (e[83] = t("div", { class: "detail-label" }, "Notes", -1)),
1363
+ t("div", ss, d(s.notes), 1)
1364
+ ])) : u("", !0),
1365
+ s.checklistProgress && s.checklistProgress.length > 0 ? (r(), a("div", is, [
1366
+ e[84] || (e[84] = t("div", { class: "detail-label" }, "Checklist Progress", -1)),
1367
+ t("div", ns, [
1368
+ t("div", {
1369
+ class: "progress-fill",
1370
+ style: S({ width: o.getChecklistProgress(s) + "%" })
1371
+ }, null, 4)
1372
+ ]),
1373
+ t("div", ls, d(o.getCompletedChecklistItems(s)) + " of " + d(s.checklistProgress.length) + " items completed (" + d(o.getChecklistProgress(s)) + "%) ", 1),
1374
+ t("div", os, [
1375
+ (r(!0), a(f, null, g(s.checklistProgress, (m, p) => (r(), a("div", {
1376
+ key: p,
1377
+ class: "checklist-item"
1378
+ }, [
1379
+ t("span", rs, d(m.completed ? "✅" : "⭕"), 1),
1380
+ t("span", null, d(m.text || "Checklist Item " + (p + 1)), 1)
1381
+ ]))), 128))
1382
+ ])
1383
+ ])) : u("", !0)
1384
+ ], 2))), 128))
1385
+ ]),
1386
+ t("div", as, [
1387
+ e[86] || (e[86] = t("div", { class: "section-title" }, "📋 Recommendations", -1)),
1388
+ t("div", ds, [
1389
+ t("ul", null, [
1390
+ (r(!0), a(f, null, g(o.generateRecommendations(), (s) => (r(), a("li", { key: s }, d(s), 1))), 128))
1391
+ ])
1392
+ ])
1393
+ ]),
1394
+ t("div", cs, [
1395
+ e[88] || (e[88] = t("div", { class: "signature-box" }, [
1396
+ t("div", null, [
1397
+ t("strong", null, "Report Generated By")
1398
+ ]),
1399
+ t("div", { style: { "margin-top": "10px", color: "#666" } }, "OceanHelm Maintenance System")
1400
+ ], -1)),
1401
+ t("div", us, [
1402
+ e[87] || (e[87] = t("div", null, [
1403
+ t("strong", null, "Date")
1404
+ ], -1)),
1405
+ t("div", ms, d(n.reportDate), 1)
1406
+ ])
1407
+ ])
1408
+ ], 512), [
1409
+ [_, n.showReport]
1410
+ ])
1411
+ ])
1412
+ ])) : u("", !0);
1413
+ }
1414
+ const hs = /* @__PURE__ */ x(_e, [["render", vs]]);
1415
+ const fs = {
1416
+ name: "ActivityLogs",
1417
+ props: {
1418
+ loading: Boolean,
1419
+ searchTerm: String,
1420
+ selectedFilter: String,
1421
+ logs: Array,
1422
+ paginatedLogs: Array,
1423
+ totalActivities: Number,
1424
+ todayActivities: Number,
1425
+ activeUsers: Number,
1426
+ totalPages: Number,
1427
+ currentPage: Number
1428
+ },
1429
+ emits: ["update:searchTerm", "update:selectedFilter", "refresh", "download", "change-page"],
1430
+ methods: {
1431
+ formatDate(i) {
1432
+ return new Date(i).toLocaleString();
1433
+ },
1434
+ getBadgeClass(i) {
1435
+ return {
1436
+ login: "badge-login",
1437
+ logout: "badge-logout",
1438
+ create: "badge-create",
1439
+ update: "badge-update",
1440
+ delete: "badge-delete",
1441
+ view: "badge-view"
1442
+ }[i] || "badge-view";
1443
+ }
1444
+ }
1445
+ }, ps = { class: "activity-logs" }, gs = { class: "controls" }, ys = { class: "search-box" }, bs = ["value"], ws = ["value"], ks = { class: "stats-grid" }, Cs = { class: "stat-card" }, _s = { class: "value" }, xs = { class: "stat-card" }, Ss = { class: "value" }, Ds = { class: "stat-card" }, As = { class: "value" }, Ts = { class: "logs-container" }, Ps = {
1446
+ key: 0,
1447
+ class: "loading"
1448
+ }, Ms = {
1449
+ key: 1,
1450
+ class: "no-logs"
1451
+ }, Es = { key: 2 }, Vs = { class: "logs-table" }, Ns = { style: { color: "gray" } }, Ls = { style: { color: "gray" } }, Fs = { class: "pagination" }, Us = ["disabled"], Is = ["onClick"], Rs = ["disabled"];
1452
+ function Os(i, e, l, v, n, o) {
1453
+ return r(), a("div", ps, [
1454
+ e[14] || (e[14] = t("div", { class: "header" }, [
1455
+ t("h1", null, "Activity Logs"),
1456
+ t("p", null, "Monitor and track all system activities in real-time")
1457
+ ], -1)),
1458
+ t("div", gs, [
1459
+ t("div", ys, [
1460
+ t("input", {
1461
+ type: "text",
1462
+ placeholder: "Search activities, users, or actions...",
1463
+ value: l.searchTerm,
1464
+ onInput: e[0] || (e[0] = (s) => i.$emit("update:searchTerm", s.target.value))
1465
+ }, null, 40, bs)
1466
+ ]),
1467
+ t("select", {
1468
+ class: "filter-select",
1469
+ value: l.selectedFilter,
1470
+ onChange: e[1] || (e[1] = (s) => i.$emit("update:selectedFilter", s.target.value))
1471
+ }, e[6] || (e[6] = [
1472
+ k('<option value="all">All Activities</option><option value="login">Login</option><option value="logout">Logout</option><option value="create">Create</option><option value="update">Update</option><option value="delete">Delete</option><option value="view">View</option>', 7)
1473
+ ]), 40, ws),
1474
+ t("button", {
1475
+ class: "btn btn-primary",
1476
+ onClick: e[2] || (e[2] = (s) => i.$emit("refresh"))
1477
+ }, "🔄 Refresh"),
1478
+ t("button", {
1479
+ class: "btn btn-secondary",
1480
+ onClick: e[3] || (e[3] = (s) => i.$emit("download"))
1481
+ }, "📥 Download Report")
1482
+ ]),
1483
+ t("div", ks, [
1484
+ t("div", Cs, [
1485
+ e[7] || (e[7] = t("h3", null, "Total Activities", -1)),
1486
+ t("div", _s, d(l.totalActivities), 1)
1487
+ ]),
1488
+ t("div", xs, [
1489
+ e[8] || (e[8] = t("h3", null, "Today's Activities", -1)),
1490
+ t("div", Ss, d(l.todayActivities), 1)
1491
+ ]),
1492
+ t("div", Ds, [
1493
+ e[9] || (e[9] = t("h3", null, "Active Users", -1)),
1494
+ t("div", As, d(l.activeUsers), 1)
1495
+ ]),
1496
+ e[10] || (e[10] = t("div", { class: "stat-card" }, [
1497
+ t("h3", null, "Important"),
1498
+ t("div", { class: "badge-danger" }, " Logs are deleted at the end of every month, please download a copy ")
1499
+ ], -1))
1500
+ ]),
1501
+ t("div", Ts, [
1502
+ l.loading ? (r(), a("div", Ps, e[11] || (e[11] = [
1503
+ t("div", { class: "spinner" }, null, -1),
1504
+ t("p", null, "Loading activity logs...", -1)
1505
+ ]))) : l.logs.length === 0 ? (r(), a("div", Ms, e[12] || (e[12] = [
1506
+ t("h3", null, "No activities found", -1),
1507
+ t("p", null, "Try adjusting your search or filter criteria", -1)
1508
+ ]))) : (r(), a("div", Es, [
1509
+ t("table", Vs, [
1510
+ e[13] || (e[13] = t("thead", null, [
1511
+ t("tr", null, [
1512
+ t("th", null, "Timestamp"),
1513
+ t("th", null, "User Name"),
1514
+ t("th", null, "Action"),
1515
+ t("th", null, "Details"),
1516
+ t("th", null, "Section")
1517
+ ])
1518
+ ], -1)),
1519
+ t("tbody", null, [
1520
+ (r(!0), a(f, null, g(l.paginatedLogs, (s) => (r(), a("tr", {
1521
+ key: s.id
1522
+ }, [
1523
+ t("td", null, d(o.formatDate(s.timestamp)), 1),
1524
+ t("td", null, [
1525
+ t("div", null, d(s.user_name), 1),
1526
+ t("small", Ns, d(s.email), 1)
1527
+ ]),
1528
+ t("td", null, [
1529
+ t("span", {
1530
+ class: h(["activity-badge", o.getBadgeClass(s.action)])
1531
+ }, d(s.action), 3)
1532
+ ]),
1533
+ t("td", null, [
1534
+ b(d(s.details.status) + " ", 1),
1535
+ (r(!0), a(f, null, g(s.details.information, (m, p) => (r(), a("div", { key: p }, [
1536
+ t("strong", null, d(p) + ": ", 1),
1537
+ t("small", Ls, d(m.from || "") + " → " + d(m.to || m), 1)
1538
+ ]))), 128))
1539
+ ]),
1540
+ t("td", null, d(s.table_name), 1)
1541
+ ]))), 128))
1542
+ ])
1543
+ ]),
1544
+ t("div", Fs, [
1545
+ t("button", {
1546
+ onClick: e[4] || (e[4] = (s) => i.$emit("change-page", l.currentPage - 1)),
1547
+ disabled: l.currentPage === 1
1548
+ }, " Previous ", 8, Us),
1549
+ (r(!0), a(f, null, g(l.totalPages, (s) => (r(), a("button", {
1550
+ key: s,
1551
+ onClick: (m) => i.$emit("change-page", s),
1552
+ class: h({ active: l.currentPage === s })
1553
+ }, d(s), 11, Is))), 128)),
1554
+ t("button", {
1555
+ onClick: e[5] || (e[5] = (s) => i.$emit("change-page", l.currentPage + 1)),
1556
+ disabled: l.currentPage === l.totalPages
1557
+ }, " Next ", 8, Rs)
1558
+ ])
1559
+ ]))
1560
+ ])
1561
+ ]);
1562
+ }
1563
+ const Bs = /* @__PURE__ */ x(fs, [["render", Os]]);
1564
+ const Hs = {
1565
+ name: "CrewManagement",
1566
+ props: {
1567
+ // Required props
1568
+ crew: {
1569
+ type: Array,
1570
+ required: !0,
1571
+ default: () => []
1572
+ },
1573
+ vesselName: {
1574
+ type: String,
1575
+ default: ""
1576
+ },
1577
+ userProfile: {
1578
+ type: Object,
1579
+ default: () => ({ role: "viewer" })
1580
+ },
1581
+ // Optional props
1582
+ loading: {
1583
+ type: Boolean,
1584
+ default: !1
1585
+ },
1586
+ availableRoles: {
1587
+ type: Array,
1588
+ default: () => ["Captain", "First Officer", "Engineer", "Deckhand", "Mechanic", "Cook"]
1589
+ },
1590
+ // Configuration props
1591
+ config: {
1592
+ type: Object,
1593
+ default: () => ({
1594
+ showWaveBackground: !0,
1595
+ enableAdd: !0,
1596
+ enableEdit: !0,
1597
+ enableDelete: !0,
1598
+ enableAssignShift: !0,
1599
+ enableCertificationManagement: !0
1600
+ })
1601
+ }
1602
+ },
1603
+ emits: [
1604
+ "crew-add",
1605
+ "crew-edit",
1606
+ "crew-delete",
1607
+ "crew-assign-shift",
1608
+ "crew-add-certification",
1609
+ "crew-view-certification",
1610
+ "search-changed",
1611
+ "filter-changed",
1612
+ "access-denied"
1613
+ ],
1614
+ data() {
1615
+ return {
1616
+ searchQuery: "",
1617
+ filterStatus: "all",
1618
+ showAddForm: !1,
1619
+ formErrors: {},
1620
+ newCrew: {
1621
+ name: "",
1622
+ role: "Deckhand",
1623
+ customRole: "",
1624
+ status: "available",
1625
+ nextShift: "",
1626
+ certifications: [{ name: "", expiryDate: "" }],
1627
+ notes: "",
1628
+ email: "",
1629
+ onBoard: ""
1630
+ }
1631
+ };
1632
+ },
1633
+ computed: {
1634
+ sectionTitle() {
1635
+ return this.vesselName ? `Current Crew for ${this.vesselName}` : "All Fleet Crew";
1636
+ },
1637
+ filteredCrew() {
1638
+ return this.crew.filter((i) => {
1639
+ const e = this.searchQuery === "" || i.name.toLowerCase().includes(this.searchQuery.toLowerCase()) || i.role.toLowerCase().includes(this.searchQuery.toLowerCase()) || i.vessel && i.vessel.toLowerCase().includes(this.searchQuery.toLowerCase()), l = this.filterStatus === "all" || i.status === this.filterStatus;
1640
+ return e && l;
1641
+ });
1642
+ },
1643
+ canAddCrew() {
1644
+ return this.config.enableAdd && this.hasPermission("add");
1645
+ },
1646
+ canEditCrew() {
1647
+ return this.config.enableEdit && this.hasPermission("edit");
1648
+ },
1649
+ canDeleteCrew() {
1650
+ return this.config.enableDelete && this.hasPermission("delete");
1651
+ },
1652
+ canAssignShift() {
1653
+ return this.config.enableAssignShift && this.hasPermission("assign");
1654
+ }
1655
+ },
1656
+ methods: {
1657
+ // Permission checking
1658
+ hasPermission(i) {
1659
+ var v;
1660
+ const { role: e } = this.userProfile;
1661
+ return ((v = {
1662
+ owner: ["add", "edit", "delete", "assign", "view"],
1663
+ staff: ["add", "edit", "assign", "view"],
1664
+ captain: ["assign", "view"],
1665
+ viewer: ["view"]
1666
+ }[e]) == null ? void 0 : v.includes(i)) || !1;
1667
+ },
1668
+ // Event handlers
1669
+ handleToggleAddForm() {
1670
+ if (!this.canAddCrew) {
1671
+ this.$emit("access-denied", { action: "add crew", userProfile: this.userProfile });
1672
+ return;
1673
+ }
1674
+ this.showAddForm = !this.showAddForm, this.showAddForm || this.resetForm();
1675
+ },
1676
+ handleSearch() {
1677
+ this.$emit("search-changed", this.searchQuery);
1678
+ },
1679
+ handleFilter() {
1680
+ this.$emit("filter-changed", this.filterStatus);
1681
+ },
1682
+ handleAddCrewMember() {
1683
+ if (!this.validateForm())
1684
+ return;
1685
+ const i = this.newCrew.certifications.filter(
1686
+ (v) => v.name.trim() !== "" && v.expiryDate !== ""
1687
+ ), e = this.newCrew.role === "Other" ? this.newCrew.customRole : this.newCrew.role, l = {
1688
+ name: this.newCrew.name,
1689
+ role: e,
1690
+ status: this.newCrew.status,
1691
+ certifications: i,
1692
+ notes: this.newCrew.notes,
1693
+ vessel: this.vesselName,
1694
+ email: this.newCrew.email,
1695
+ onBoard: this.newCrew.onBoard,
1696
+ nextShift: this.newCrew.nextShift
1697
+ };
1698
+ this.$emit("crew-add", l), this.resetForm(), this.showAddForm = !1;
1699
+ },
1700
+ handleCancelForm() {
1701
+ this.showAddForm = !1, this.resetForm();
1702
+ },
1703
+ handleDeleteCrew(i) {
1704
+ if (!this.canDeleteCrew) {
1705
+ this.$emit("access-denied", { action: "delete crew", userProfile: this.userProfile });
1706
+ return;
1707
+ }
1708
+ this.$emit("crew-delete", i);
1709
+ },
1710
+ handleAssignShift(i) {
1711
+ if (!this.canAssignShift) {
1712
+ this.$emit("access-denied", { action: "assign shift", userProfile: this.userProfile });
1713
+ return;
1714
+ }
1715
+ this.$emit("crew-assign-shift", i);
1716
+ },
1717
+ handleAddCertification(i) {
1718
+ if (!this.canEditCrew) {
1719
+ this.$emit("access-denied", { action: "add certification", userProfile: this.userProfile });
1720
+ return;
1721
+ }
1722
+ this.$emit("crew-add-certification", i);
1723
+ },
1724
+ handleViewCertification(i, e) {
1725
+ this.$emit("crew-view-certification", { certification: i, member: e });
1726
+ },
1727
+ // Form management
1728
+ resetForm() {
1729
+ this.newCrew = {
1730
+ name: "",
1731
+ role: "Deckhand",
1732
+ customRole: "",
1733
+ status: "available",
1734
+ nextShift: "",
1735
+ certifications: [{ name: "", expiryDate: "" }],
1736
+ notes: "",
1737
+ email: "",
1738
+ onBoard: ""
1739
+ }, this.formErrors = {};
1740
+ },
1741
+ validateForm() {
1742
+ this.formErrors = {};
1743
+ const i = {
1744
+ name: "Full Name",
1745
+ email: "Email Address"
1746
+ };
1747
+ return Object.keys(i).forEach((e) => {
1748
+ (!this.newCrew[e] || this.newCrew[e].trim() === "") && (this.formErrors[e] = `${i[e]} is required`);
1749
+ }), this.newCrew.email && !this.isValidEmail(this.newCrew.email) && (this.formErrors.email = "Please enter a valid email address"), this.newCrew.role === "Other" && (!this.newCrew.customRole || this.newCrew.customRole.trim() === "") && (this.formErrors.customRole = 'Custom role is required when "Other" is selected'), Object.keys(this.formErrors).length === 0;
1750
+ },
1751
+ isValidEmail(i) {
1752
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i);
1753
+ },
1754
+ addCertificationEntry() {
1755
+ this.newCrew.certifications.push({ name: "", expiryDate: "" });
1756
+ },
1757
+ removeCertification(i) {
1758
+ this.newCrew.certifications.splice(i, 1);
1759
+ },
1760
+ // Utility methods
1761
+ formatStatus(i) {
1762
+ return i ? i.charAt(0).toUpperCase() + i.slice(1) : "";
1763
+ },
1764
+ getStatusClass(i) {
1765
+ return {
1766
+ available: "status-available",
1767
+ onduty: "status-onduty",
1768
+ unavailable: "status-unavailable"
1769
+ }[i] || "";
1770
+ },
1771
+ getCertificationClass(i) {
1772
+ const e = this.getExpiryStatus(i);
1773
+ return {
1774
+ expired: "text-danger",
1775
+ expiringSoon: "text-warning",
1776
+ valid: "text-success"
1777
+ }[e] || "";
1778
+ },
1779
+ getExpiryStatus(i) {
1780
+ if (!i)
1781
+ return "none";
1782
+ const e = new Date(i), l = /* @__PURE__ */ new Date(), v = /* @__PURE__ */ new Date();
1783
+ return v.setMonth(l.getMonth() + 1), e <= l ? "expired" : e <= v ? "expiringSoon" : "valid";
1784
+ }
1785
+ }
1786
+ }, qs = { class: "crew-management" }, js = {
1787
+ key: 0,
1788
+ class: "wave-bg"
1789
+ }, $s = { class: "crew-section" }, Qs = { class: "section-header" }, zs = { class: "search-filter" }, Ys = {
1790
+ key: 0,
1791
+ class: "loading-state"
1792
+ }, Ks = {
1793
+ key: 1,
1794
+ class: "crew-grid"
1795
+ }, Ws = { class: "crew-name" }, Gs = { class: "crew-role" }, Js = { class: "crew-certifications" }, Xs = ["onClick"], Zs = ["onClick"], ei = { class: "crew-availability" }, ti = { class: "crew-availability" }, si = { class: "action-buttons" }, ii = {
1796
+ key: 0,
1797
+ class: "status-available crew-availability vcard"
1798
+ }, ni = {
1799
+ key: 1,
1800
+ class: "status-unavailable crew-availability vcard"
1801
+ }, li = ["onClick"], oi = ["onClick"], ri = {
1802
+ key: 2,
1803
+ class: "no-results"
1804
+ }, ai = {
1805
+ key: 3,
1806
+ class: "add-crew-form"
1807
+ }, di = { class: "form-row" }, ci = { class: "form-group" }, ui = {
1808
+ key: 0,
1809
+ class: "error-message"
1810
+ }, mi = { class: "form-group" }, vi = ["value"], hi = { class: "form-row" }, fi = { class: "form-group" }, pi = { class: "form-group" }, gi = {
1811
+ key: 0,
1812
+ class: "error-message"
1813
+ }, yi = { class: "certification-section" }, bi = { class: "form-row" }, wi = { class: "form-group" }, ki = ["onUpdate:modelValue"], Ci = { class: "form-group" }, _i = ["onUpdate:modelValue"], xi = { class: "form-group" }, Si = ["onClick"], Di = { class: "form-row" }, Ai = { class: "form-group" }, Ti = { class: "form-actions" };
1814
+ function Pi(i, e, l, v, n, o) {
1815
+ return r(), a("div", qs, [
1816
+ l.config.showWaveBackground ? (r(), a("div", js)) : u("", !0),
1817
+ t("div", $s, [
1818
+ t("div", Qs, [
1819
+ t("h2", null, d(o.sectionTitle), 1),
1820
+ o.canAddCrew ? (r(), a("button", {
1821
+ key: 0,
1822
+ class: "btn btn-primary",
1823
+ onClick: e[0] || (e[0] = (...s) => o.handleToggleAddForm && o.handleToggleAddForm(...s))
1824
+ }, d(n.showAddForm ? "Cancel" : "+ Add Crew Member"), 1)) : u("", !0)
1825
+ ]),
1826
+ t("div", zs, [
1827
+ c(t("input", {
1828
+ type: "text",
1829
+ placeholder: "Search crew by name or role...",
1830
+ "onUpdate:modelValue": e[1] || (e[1] = (s) => n.searchQuery = s),
1831
+ onInput: e[2] || (e[2] = (...s) => o.handleSearch && o.handleSearch(...s))
1832
+ }, null, 544), [
1833
+ [y, n.searchQuery]
1834
+ ]),
1835
+ c(t("select", {
1836
+ "onUpdate:modelValue": e[3] || (e[3] = (s) => n.filterStatus = s),
1837
+ onChange: e[4] || (e[4] = (...s) => o.handleFilter && o.handleFilter(...s))
1838
+ }, e[14] || (e[14] = [
1839
+ t("option", { value: "all" }, "All Statuses", -1),
1840
+ t("option", { value: "available" }, "Available", -1),
1841
+ t("option", { value: "onduty" }, "On Duty", -1),
1842
+ t("option", { value: "unavailable" }, "Unavailable", -1)
1843
+ ]), 544), [
1844
+ [w, n.filterStatus]
1845
+ ])
1846
+ ]),
1847
+ l.loading ? (r(), a("div", Ys, e[15] || (e[15] = [
1848
+ t("div", {
1849
+ class: "spinner-border text-primary",
1850
+ role: "status"
1851
+ }, [
1852
+ t("span", { class: "visually-hidden" }, "Loading crew...")
1853
+ ], -1),
1854
+ t("p", null, "Loading crew members...", -1)
1855
+ ]))) : o.filteredCrew.length > 0 ? (r(), a("div", Ks, [
1856
+ (r(!0), a(f, null, g(o.filteredCrew, (s) => (r(), a("div", {
1857
+ key: s.id,
1858
+ class: h(["crew-card", { unavailable: s.status === "unavailable" }])
1859
+ }, [
1860
+ t("div", {
1861
+ class: h(["status-badge", o.getStatusClass(s.status)])
1862
+ }, d(o.formatStatus(s.status)), 3),
1863
+ t("div", Ws, d(s.name), 1),
1864
+ t("div", Gs, d(s.role), 1),
1865
+ t("div", Js, [
1866
+ (r(!0), a(f, null, g(s.certifications, (m) => (r(), a("div", {
1867
+ key: m.name,
1868
+ class: h(["certification-tag", o.getCertificationClass(m.expiryDate)]),
1869
+ onClick: (p) => o.handleViewCertification(m, s)
1870
+ }, d(m.name), 11, Xs))), 128)),
1871
+ o.canEditCrew ? (r(), a("i", {
1872
+ key: 0,
1873
+ class: "bi bi-patch-plus-fill icon",
1874
+ onClick: (m) => o.handleAddCertification(s)
1875
+ }, null, 8, Zs)) : u("", !0)
1876
+ ]),
1877
+ t("div", ei, [
1878
+ e[16] || (e[16] = t("strong", null, "Embarkation Date:", -1)),
1879
+ b(" " + d(s.nextShift || "Not Scheduled"), 1)
1880
+ ]),
1881
+ t("div", ti, [
1882
+ e[17] || (e[17] = t("strong", null, "Expected Days Onboard (in days):", -1)),
1883
+ b(" " + d(s.onBoard || "Not Scheduled"), 1)
1884
+ ]),
1885
+ t("div", si, [
1886
+ s.vessel ? (r(), a("div", ii, " Vessel: " + d(s.vessel), 1)) : (r(), a("div", ni, " Vessel: Unassigned ")),
1887
+ o.canAssignShift ? (r(), a("button", {
1888
+ key: 2,
1889
+ class: "btn btn-primary",
1890
+ onClick: (m) => o.handleAssignShift(s)
1891
+ }, " Assign Shift ", 8, li)) : u("", !0)
1892
+ ]),
1893
+ o.canDeleteCrew ? (r(), a("i", {
1894
+ key: 0,
1895
+ class: "bi bi-trash icon delete-icon",
1896
+ onClick: (m) => o.handleDeleteCrew(s)
1897
+ }, null, 8, oi)) : u("", !0)
1898
+ ], 2))), 128))
1899
+ ])) : l.loading ? u("", !0) : (r(), a("div", ri, d(l.crew.length === 0 ? "No crew members found." : "No crew members found matching your search criteria."), 1)),
1900
+ n.showAddForm ? (r(), a("div", ai, [
1901
+ e[28] || (e[28] = t("h2", null, "Add New Crew Member", -1)),
1902
+ t("div", di, [
1903
+ t("div", ci, [
1904
+ e[18] || (e[18] = t("label", { for: "crew-name" }, "Full Name *", -1)),
1905
+ c(t("input", {
1906
+ type: "text",
1907
+ id: "crew-name",
1908
+ "onUpdate:modelValue": e[5] || (e[5] = (s) => n.newCrew.name = s),
1909
+ class: h({ error: n.formErrors.name })
1910
+ }, null, 2), [
1911
+ [y, n.newCrew.name]
1912
+ ]),
1913
+ n.formErrors.name ? (r(), a("div", ui, d(n.formErrors.name), 1)) : u("", !0)
1914
+ ]),
1915
+ t("div", mi, [
1916
+ e[20] || (e[20] = t("label", { for: "crew-role" }, "Role/Position *", -1)),
1917
+ c(t("select", {
1918
+ id: "crew-role",
1919
+ "onUpdate:modelValue": e[6] || (e[6] = (s) => n.newCrew.role = s)
1920
+ }, [
1921
+ (r(!0), a(f, null, g(l.availableRoles, (s) => (r(), a("option", {
1922
+ key: s,
1923
+ value: s
1924
+ }, d(s), 9, vi))), 128)),
1925
+ e[19] || (e[19] = t("option", { value: "Other" }, "Other", -1))
1926
+ ], 512), [
1927
+ [w, n.newCrew.role]
1928
+ ]),
1929
+ n.newCrew.role === "Other" ? c((r(), a("input", {
1930
+ key: 0,
1931
+ type: "text",
1932
+ placeholder: "Enter custom role",
1933
+ "onUpdate:modelValue": e[7] || (e[7] = (s) => n.newCrew.customRole = s),
1934
+ style: { "margin-top": "8px" }
1935
+ }, null, 512)), [
1936
+ [y, n.newCrew.customRole]
1937
+ ]) : u("", !0)
1938
+ ])
1939
+ ]),
1940
+ t("div", hi, [
1941
+ t("div", fi, [
1942
+ e[22] || (e[22] = t("label", { for: "crew-status" }, "Status *", -1)),
1943
+ c(t("select", {
1944
+ id: "crew-status",
1945
+ "onUpdate:modelValue": e[8] || (e[8] = (s) => n.newCrew.status = s)
1946
+ }, e[21] || (e[21] = [
1947
+ t("option", { value: "available" }, "Available", -1),
1948
+ t("option", { value: "onduty" }, "On Duty", -1),
1949
+ t("option", { value: "unavailable" }, "Unavailable", -1)
1950
+ ]), 512), [
1951
+ [w, n.newCrew.status]
1952
+ ])
1953
+ ]),
1954
+ t("div", pi, [
1955
+ e[23] || (e[23] = t("label", { for: "crew-email" }, "Email Address *", -1)),
1956
+ c(t("input", {
1957
+ type: "email",
1958
+ id: "crew-email",
1959
+ "onUpdate:modelValue": e[9] || (e[9] = (s) => n.newCrew.email = s),
1960
+ class: h({ error: n.formErrors.email })
1961
+ }, null, 2), [
1962
+ [y, n.newCrew.email]
1963
+ ]),
1964
+ n.formErrors.email ? (r(), a("div", gi, d(n.formErrors.email), 1)) : u("", !0)
1965
+ ])
1966
+ ]),
1967
+ t("div", yi, [
1968
+ e[26] || (e[26] = t("h3", null, "Certifications", -1)),
1969
+ (r(!0), a(f, null, g(n.newCrew.certifications, (s, m) => (r(), a("div", {
1970
+ key: m,
1971
+ class: "certification-entry"
1972
+ }, [
1973
+ t("div", bi, [
1974
+ t("div", wi, [
1975
+ e[24] || (e[24] = t("label", null, "Certification Name", -1)),
1976
+ c(t("input", {
1977
+ type: "text",
1978
+ "onUpdate:modelValue": (p) => s.name = p,
1979
+ placeholder: "Enter certification name"
1980
+ }, null, 8, ki), [
1981
+ [y, s.name]
1982
+ ])
1983
+ ]),
1984
+ t("div", Ci, [
1985
+ e[25] || (e[25] = t("label", null, "Expiry Date", -1)),
1986
+ c(t("input", {
1987
+ type: "date",
1988
+ "onUpdate:modelValue": (p) => s.expiryDate = p
1989
+ }, null, 8, _i), [
1990
+ [y, s.expiryDate]
1991
+ ])
1992
+ ]),
1993
+ t("div", xi, [
1994
+ n.newCrew.certifications.length > 1 ? (r(), a("button", {
1995
+ key: 0,
1996
+ type: "button",
1997
+ class: "btn btn-danger btn-sm",
1998
+ onClick: (p) => o.removeCertification(m)
1999
+ }, " Remove ", 8, Si)) : u("", !0)
2000
+ ])
2001
+ ])
2002
+ ]))), 128)),
2003
+ t("button", {
2004
+ type: "button",
2005
+ class: "btn btn-secondary btn-sm",
2006
+ onClick: e[10] || (e[10] = (...s) => o.addCertificationEntry && o.addCertificationEntry(...s))
2007
+ }, " + Add More Certification ")
2008
+ ]),
2009
+ t("div", Di, [
2010
+ t("div", Ai, [
2011
+ e[27] || (e[27] = t("label", { for: "crew-notes" }, "Notes", -1)),
2012
+ c(t("textarea", {
2013
+ id: "crew-notes",
2014
+ rows: "3",
2015
+ "onUpdate:modelValue": e[11] || (e[11] = (s) => n.newCrew.notes = s)
2016
+ }, null, 512), [
2017
+ [y, n.newCrew.notes]
2018
+ ])
2019
+ ])
2020
+ ]),
2021
+ t("div", Ti, [
2022
+ t("button", {
2023
+ class: "btn btn-secondary",
2024
+ onClick: e[12] || (e[12] = (...s) => o.handleCancelForm && o.handleCancelForm(...s))
2025
+ }, "Cancel"),
2026
+ t("button", {
2027
+ class: "btn btn-primary",
2028
+ onClick: e[13] || (e[13] = (...s) => o.handleAddCrewMember && o.handleAddCrewMember(...s))
2029
+ }, "Add Crew Member")
2030
+ ])
2031
+ ])) : u("", !0)
2032
+ ])
2033
+ ]);
2034
+ }
2035
+ const Mi = /* @__PURE__ */ x(Hs, [["render", Pi]]), Ni = (i = {}) => ({
2036
+ brandName: i.brandName || "OceanHelm",
2037
+ logoIcon: i.logoIcon || "bi bi-water",
2038
+ showLogo: i.showLogo !== !1,
2039
+ responsive: i.responsive !== !1,
2040
+ ...i
2041
+ }), Li = [
2042
+ {
2043
+ type: "link",
2044
+ label: "Dashboard",
2045
+ icon: "bi bi-speedometer2",
2046
+ href: "/app/dashboard",
2047
+ active: !0
2048
+ },
2049
+ {
2050
+ type: "link",
2051
+ label: "Activity Log",
2052
+ icon: "bi bi-activity",
2053
+ href: "/activity-log",
2054
+ roles: ["owner"]
2055
+ // Role-based visibility
2056
+ },
2057
+ {
2058
+ type: "text",
2059
+ label: "Services"
2060
+ },
2061
+ {
2062
+ type: "button",
2063
+ label: "Maintenance",
2064
+ icon: "bi bi-tools",
2065
+ action: "maintenance"
2066
+ },
2067
+ {
2068
+ type: "dropdown",
2069
+ label: "Crew Management",
2070
+ icon: "bi bi-people",
2071
+ children: [
2072
+ {
2073
+ label: "All Crew",
2074
+ action: "crew-all",
2075
+ roles: ["owner", "staff"]
2076
+ },
2077
+ {
2078
+ type: "separator"
2079
+ },
2080
+ {
2081
+ label: "Get Crew by Vessel",
2082
+ action: "crew-by-vessel"
2083
+ }
2084
+ ]
2085
+ },
2086
+ {
2087
+ type: "link",
2088
+ label: "Inventory Management",
2089
+ icon: "bi bi-clipboard-data",
2090
+ href: "/app/inventory"
2091
+ },
2092
+ {
2093
+ type: "link",
2094
+ label: "Requisition Processing",
2095
+ icon: "bi bi-calendar-check",
2096
+ href: "/app/requisition"
2097
+ },
2098
+ {
2099
+ type: "button",
2100
+ label: "Voyage Manager",
2101
+ icon: "fas fa-ship",
2102
+ action: "coming-soon"
2103
+ },
2104
+ {
2105
+ type: "button",
2106
+ label: "Settings",
2107
+ icon: "bi bi-gear",
2108
+ action: "settings",
2109
+ roles: ["owner", "staff"]
2110
+ },
2111
+ {
2112
+ type: "button",
2113
+ label: "Help & Support",
2114
+ icon: "bi bi-question-circle",
2115
+ action: "help"
2116
+ }
2117
+ ], Fi = (i, e) => !i.roles || i.roles.length === 0 ? !0 : i.roles.includes(e == null ? void 0 : e.role), Ui = {
2118
+ install(i, e = {}) {
2119
+ i.component("ConfigurableSidebar", H), i.component("VesselList", pe), i.component("DashHead", Ce), i.component("ActivityLogs", Bs), i.component("CrewManagement", Mi), i.component("DashHead", hs), i.provide("sidebarConfig", e);
2120
+ }
2121
+ };
2122
+ export {
2123
+ Bs as ActivityLogs,
2124
+ H as ConfigurableSidebar,
2125
+ Mi as CrewManagement,
2126
+ Ce as DashHead,
2127
+ hs as OceanHelmMaintenance,
2128
+ pe as VesselList,
2129
+ Ni as createSidebarConfig,
2130
+ Ui as default,
2131
+ Li as defaultMenuItems,
2132
+ Fi as defaultPermissionChecker
2133
+ };
2134
+ //# sourceMappingURL=oceanhelm.es.js.map