oceanhelm 0.0.11 → 0.0.13

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.
@@ -19,7 +19,7 @@
19
19
  <div class="form-grid">
20
20
  <div class="form-group">
21
21
  <label>Requestor Name *</label>
22
- <input type="text" :value="userProfile.full_name" readonly required class="form-control" />
22
+ <input type="text" :value="userProfile?.full_name" readonly required class="form-control" />
23
23
  </div>
24
24
  <div class="form-group">
25
25
  <label>Department *</label>
@@ -39,7 +39,7 @@
39
39
  </div>
40
40
  <div class="form-group">
41
41
  <label>Date Needed *</label>
42
- <input type="date" v-model="form.neededDate" required />
42
+ <input type="date" v-model="form.neededDate" :min="today" required />
43
43
  </div>
44
44
  </div>
45
45
 
@@ -76,7 +76,7 @@
76
76
  </div>
77
77
  <div class="form-group">
78
78
  <label>Est. Unit Cost *</label>
79
- <input type="number" v-model.number="item.cost" step="0.01" placeholder="0.00" required />
79
+ <input type="number" v-model.number="item.cost" step="0.01" min="0" placeholder="0.00" required />
80
80
  </div>
81
81
  <button type="button" class="remove-item-btn" @click="removeItem(index)">Remove</button>
82
82
  </div>
@@ -84,7 +84,9 @@
84
84
  </div>
85
85
 
86
86
  <div class="action-buttons">
87
- <button type="submit" class="btn btn-primary-req">Submit Requisition</button>
87
+ <button type="submit" class="btn btn-primary-req" :disabled="isSubmitting">
88
+ {{ isSubmitting ? 'Submitting...' : 'Submit Requisition' }}
89
+ </button>
88
90
  </div>
89
91
  </form>
90
92
  </div>
@@ -270,23 +272,23 @@
270
272
  <h3>Vendor Information</h3>
271
273
  <div class="info-row">
272
274
  <span class="info-label">Company:</span>
273
- <span class="info-value">{{ vendorInfo.company || poDetails.vendorInfo?.company }} </span>
275
+ <span class="info-value">{{ vendorInfo.company || poDetails.vendorInfo?.company || 'N/A' }} </span>
274
276
  </div>
275
277
  <div class="info-row">
276
278
  <span class="info-label">Contact:</span>
277
- <span class="info-value">{{ vendorInfo.contact || poDetails.vendorInfo?.contact }}</span>
279
+ <span class="info-value">{{ vendorInfo.contact || poDetails.vendorInfo?.contact || 'N/A' }}</span>
278
280
  </div>
279
281
  <div class="info-row">
280
282
  <span class="info-label">Email:</span>
281
- <span class="info-value">{{ vendorInfo.email || poDetails.vendorInfo?.email }}</span>
283
+ <span class="info-value">{{ vendorInfo.email || poDetails.vendorInfo?.email || 'N/A' }}</span>
282
284
  </div>
283
285
  <div class="info-row">
284
286
  <span class="info-label">Phone:</span>
285
- <span class="info-value">{{ vendorInfo.phone || poDetails.vendorInfo?.phone }}</span>
287
+ <span class="info-label">{{ vendorInfo.phone || poDetails.vendorInfo?.phone || 'N/A' }}</span>
286
288
  </div>
287
289
  <div class="info-row">
288
290
  <span class="info-label">Address:</span>
289
- <span class="info-value">{{ vendorInfo.address || poDetails.vendorInfo?.address }}</span>
291
+ <span class="info-value">{{ vendorInfo.address || poDetails.vendorInfo?.address || 'N/A' }}</span>
290
292
  </div>
291
293
  </div>
292
294
 
@@ -298,19 +300,19 @@
298
300
  </div>
299
301
  <div class="info-row">
300
302
  <span class="info-label">Date:</span>
301
- <span class="info-value">{{ vendorInfo.poDate || poDetails.vendorInfo?.poDate }}</span>
303
+ <span class="info-value">{{ vendorInfo.poDate || poDetails.vendorInfo?.poDate || formatDate(new Date()) }}</span>
302
304
  </div>
303
305
  <div class="info-row">
304
306
  <span class="info-label">Requested By:</span>
305
- <span class="info-value">{{ vendorInfo.poApproved || poDetails.vendorInfo?.poApproved }}</span>
307
+ <span class="info-value">{{ vendorInfo.poApproved || poDetails.vendorInfo?.poApproved || 'N/A' }}</span>
306
308
  </div>
307
309
  <div class="info-row">
308
310
  <span class="info-label">Department:</span>
309
- <span class="info-value">PO-{{ poDetails.department }}</span>
311
+ <span class="info-value">PO-{{ poDetails.department || 'N/A' }}</span>
310
312
  </div>
311
313
  <div class="info-row">
312
314
  <span class="info-label">Delivery Date:</span>
313
- <span class="info-value">{{ poDetails.neededDate }}</span>
315
+ <span class="info-value">{{ poDetails.neededDate || 'N/A' }}</span>
314
316
  </div>
315
317
  </div>
316
318
  </div>
@@ -330,18 +332,18 @@
330
332
  </thead>
331
333
  <tbody>
332
334
  <tr v-for="(item, index) in poDetails.items || []" :key="index">
333
- <td>{{ item.itemNumber }}</td>
335
+ <td>{{ item.itemNumber || (index + 1) }}</td>
334
336
  <td>{{ item.desc }}</td>
335
337
  <td>{{ item.qty }}</td>
336
338
  <td>
337
339
  <span v-if="!item.editing">
338
- ${{ item.cost.toFixed(2) }}
339
- <span v-if="item.cost !== item.unitPrice" class="price-change-indicator">!</span>
340
+ ${{ (item.unitPrice || item.cost || 0).toFixed(2) }}
341
+ <span v-if="item.cost !== item.unitPrice && item.unitPrice" class="price-change-indicator">!</span>
340
342
  </span>
341
- <input v-else v-model.number="item.tempPrice" type="number" step="0.01"
343
+ <input v-else v-model.number="item.tempPrice" type="number" step="0.01" min="0"
342
344
  class="price-input" :class="{ 'price-changed': item.cost !== item.tempPrice }">
343
345
  </td>
344
- <td>${{ (item.unitPrice * item.qty).toFixed(2) }}</td>
346
+ <td>${{ ((item.unitPrice || item.cost || 0) * (item.qty || 0)).toFixed(2) }}</td>
345
347
  <td v-if="!isPrinting">
346
348
  <button v-if="!item.editing" @click="startEdit(index)" class="edit-btn">
347
349
  Edit Price
@@ -357,7 +359,7 @@
357
359
 
358
360
  <div v-for="(item, index) in poDetails.items || []" :key="'note-' + index">
359
361
  <div v-if="item.justification" class="justification-note">
360
- <strong>Price Change Justification (Item {{ item.itemNumber }}):</strong> {{ item.justification
362
+ <strong>Price Change Justification (Item {{ item.itemNumber || (index + 1) }}):</strong> {{ item.justification
361
363
  }}
362
364
  </div>
363
365
  </div>
@@ -368,8 +370,8 @@
368
370
  <span>${{ subTotal.toFixed(2) }}</span>
369
371
  </div>
370
372
  <div class="total-row">
371
- <span>Tax (%):</span>
372
- <span>${{ getOptional(vendorInfo.tax) }}</span>
373
+ <span>Tax ({{ vendorInfo.tax || poDetails.vendorInfo?.tax || 0 }}%):</span>
374
+ <span>${{ calculateTax().toFixed(2) }}</span>
373
375
  </div>
374
376
  <div class="total-row">
375
377
  <span>Shipping:</span>
@@ -377,8 +379,7 @@
377
379
  </div>
378
380
  <div class="total-row grand-total">
379
381
  <span>Grand Total:</span>
380
- <span>${{ (subTotal + getOptional(vendorInfo.tax) + getOptional(vendorInfo.shipping)).toFixed(2)
381
- }}</span>
382
+ <span>${{ grandTotal.toFixed(2) }}</span>
382
383
  </div>
383
384
  </div>
384
385
  </div>
@@ -499,6 +500,7 @@ export default {
499
500
  activeTab: 'workflow',
500
501
  isPrinting: false,
501
502
  infoResponse: '',
503
+ isSubmitting: false,
502
504
 
503
505
  // Tabs with visibility rules
504
506
  tabs: [
@@ -536,7 +538,7 @@ export default {
536
538
  { label: 'Department', value: req => req.department },
537
539
  { label: 'Project', value: req => req.project || 'N/A' },
538
540
  { label: 'Submitted', value: req => req.submittedDate },
539
- { label: 'Items', value: req => `${req.items.length} item(s)` }
541
+ { label: 'Items', value: req => `${req.items?.length || 0} item(s)` }
540
542
  ],
541
543
 
542
544
  // Fields for My Requisitions display
@@ -573,26 +575,35 @@ export default {
573
575
  },
574
576
 
575
577
  computed: {
578
+ today() {
579
+ return new Date().toISOString().split('T')[0];
580
+ },
581
+
576
582
  visibleTabs() {
577
- return this.tabs.filter(tab => tab.roles.includes(this.userRole))
583
+ return this.tabs.filter(tab => tab.roles.includes(this.userRole));
578
584
  },
579
585
 
580
586
  subTotal() {
581
587
  return (this.poDetails.items || []).reduce((sum, item) => {
582
- return sum + (item.unitPrice * item.qty);
588
+ const unitPrice = item.unitPrice || item.cost || 0;
589
+ return sum + (unitPrice * (item.qty || 0));
583
590
  }, 0);
584
591
  },
585
592
 
593
+ grandTotal() {
594
+ return this.subTotal + this.calculateTax() + parseFloat(this.getOptional(this.vendorInfo.shipping));
595
+ },
596
+
586
597
  reviewRequisitions() {
587
- return this.requisitions.filter(r => r.status === 'under-review');
598
+ return (this.requisitions || []).filter(r => r.status === 'under-review');
588
599
  },
589
600
 
590
601
  poRequisitions() {
591
- return this.requisitions.filter(r => r.status === 'approved');
602
+ return (this.requisitions || []).filter(r => r.status === 'approved');
592
603
  },
593
604
 
594
605
  awaitingDelivery() {
595
- return this.requisitions.filter(r => r.status === 'po-created');
606
+ return (this.requisitions || []).filter(r => r.status === 'po-created');
596
607
  },
597
608
 
598
609
  currentItem() {
@@ -600,8 +611,8 @@ export default {
600
611
  },
601
612
 
602
613
  myRequisitions() {
603
- const userId = this.userProfile.id || this.userProfile.profile_id;
604
- return this.requisitions.filter(req => req.profile_id == userId);
614
+ const userId = this.userProfile?.id || this.userProfile?.profile_id;
615
+ return (this.requisitions || []).filter(req => req.profile_id == userId);
605
616
  }
606
617
  },
607
618
 
@@ -610,8 +621,19 @@ export default {
610
621
  this.activeTab = tabName;
611
622
  },
612
623
 
624
+ formatDate(dateString) {
625
+ if (!dateString) return 'N/A';
626
+ const date = new Date(dateString);
627
+ return date.toLocaleDateString();
628
+ },
629
+
630
+ calculateTax() {
631
+ const taxRate = parseFloat(this.vendorInfo.tax || this.poDetails.vendorInfo?.tax || 0);
632
+ return (this.subTotal * taxRate) / 100;
633
+ },
634
+
613
635
  getOptional(value) {
614
- return typeof value === 'number' ? value.toFixed(2) : '0.00';
636
+ return typeof value === 'number' ? value.toFixed(2) : (parseFloat(value) || 0).toFixed(2);
615
637
  },
616
638
 
617
639
  getRequisitionFields(req) {
@@ -626,21 +648,21 @@ export default {
626
648
  qty: 1,
627
649
  unit: 'Pieces',
628
650
  cost: 0
629
- })
651
+ });
630
652
  },
631
653
 
632
654
  removeItem(index) {
633
- this.form.items.splice(index, 1)
655
+ this.form.items.splice(index, 1);
634
656
  },
635
657
 
636
658
  startEdit(index) {
637
659
  this.poDetails.items[index].editing = true;
638
- this.poDetails.items[index].tempPrice = this.poDetails.items[index].unitPrice;
660
+ this.poDetails.items[index].tempPrice = this.poDetails.items[index].unitPrice || this.poDetails.items[index].cost;
639
661
  },
640
662
 
641
663
  cancelEdit(index) {
642
664
  this.poDetails.items[index].editing = false;
643
- this.poDetails.items[index].tempPrice = this.poDetails.items[index].unitPrice;
665
+ this.poDetails.items[index].tempPrice = this.poDetails.items[index].unitPrice || this.poDetails.items[index].cost;
644
666
  },
645
667
 
646
668
  savePrice(index) {
@@ -679,9 +701,19 @@ export default {
679
701
 
680
702
  // Event handlers that emit to parent
681
703
  handleSubmitRequisition() {
704
+ if (this.form.items.length === 0) {
705
+ alert('Please add at least one item to the requisition.');
706
+ return;
707
+ }
708
+
709
+ this.isSubmitting = true;
682
710
  const requisition = this.collectFormData('under-review');
683
711
  this.$emit('submit-requisition', requisition);
684
- this.resetForm();
712
+
713
+ setTimeout(() => {
714
+ this.resetForm();
715
+ this.isSubmitting = false;
716
+ }, 1000);
685
717
  },
686
718
 
687
719
  handleSubmitInfoResponse(req) {
@@ -724,7 +756,7 @@ export default {
724
756
  collectFormData(status) {
725
757
  return {
726
758
  id: 'REQ-' + Date.now(),
727
- requestor: this.userProfile.full_name,
759
+ requestor: this.userProfile?.full_name || 'Unknown',
728
760
  department: this.form.department,
729
761
  project: this.form.project,
730
762
  neededDate: this.form.neededDate,
@@ -732,8 +764,8 @@ export default {
732
764
  items: this.form.items.map(item => ({ ...item })),
733
765
  status,
734
766
  submittedDate: new Date().toLocaleDateString(),
735
- profile_id: this.userProfile.id || this.userProfile.profile_id
736
- }
767
+ profile_id: this.userProfile?.id || this.userProfile?.profile_id
768
+ };
737
769
  },
738
770
 
739
771
  resetForm() {
@@ -744,24 +776,24 @@ export default {
744
776
  neededDate: '',
745
777
  justification: '',
746
778
  items: []
747
- }
779
+ };
748
780
  // Add initial item row again
749
- this.addItem()
781
+ this.addItem();
750
782
  },
751
783
 
752
784
  // Methods for updating PO details from parent
753
785
  updatePODetails(details) {
754
- this.poDetails = details;
786
+ this.poDetails = { ...details };
755
787
  this.getNumber();
756
- for (let item of this.poDetails.items) {
757
- item.tempPrice = item.cost;
758
- item.unitPrice = item.cost;
759
- item.subTotal = item.unitPrice * item.qty;
788
+ for (let item of this.poDetails.items || []) {
789
+ item.tempPrice = item.cost || 0;
790
+ item.unitPrice = item.unitPrice || item.cost || 0;
791
+ item.subTotal = item.unitPrice * (item.qty || 0);
760
792
  }
761
793
  },
762
794
 
763
795
  updateVendorInfo(info) {
764
- this.vendorInfo = info;
796
+ this.vendorInfo = { ...info };
765
797
  },
766
798
 
767
799
  setPrintingMode(isPrinting) {
@@ -771,13 +803,13 @@ export default {
771
803
  getNumber() {
772
804
  return (this.poDetails.items || []).map((item, index) => {
773
805
  return item.itemNumber = index + 1;
774
- })
806
+ });
775
807
  }
776
808
  },
777
809
 
778
810
  created() {
779
811
  // Initialize form with one item row
780
- this.addItem()
812
+ this.addItem();
781
813
  }
782
814
  }
783
815
  </script>
@@ -814,16 +846,11 @@ export default {
814
846
  background: #f8fafc;
815
847
  border-bottom: 2px solid #e2e8f0;
816
848
  overflow-x: auto;
817
- /* enable horizontal scroll */
818
849
  white-space: nowrap;
819
- /* prevent wrapping */
820
850
  -webkit-overflow-scrolling: touch;
821
- /* smooth scrolling on mobile */
822
851
  scrollbar-width: thin;
823
- /* optional: thinner scrollbar in Firefox */
824
852
  }
825
853
 
826
- /* Optional: style the scrollbar (Webkit browsers only) */
827
854
  .nav-tabs::-webkit-scrollbar {
828
855
  height: 6px;
829
856
  }
@@ -1002,14 +1029,11 @@ export default {
1002
1029
 
1003
1030
  .item-list li {
1004
1031
  background: #f1f5f9;
1005
- /* Light blue-gray background */
1006
1032
  margin-bottom: 0.5rem;
1007
1033
  padding: 0.5rem 0.75rem;
1008
1034
  border-radius: 0.375rem;
1009
- /* Rounded corners */
1010
1035
  font-size: 0.95rem;
1011
1036
  color: #1e293b;
1012
- /* Dark text */
1013
1037
  display: flex;
1014
1038
  justify-content: space-between;
1015
1039
  align-items: center;
@@ -1276,7 +1300,10 @@ export default {
1276
1300
  border-top: 2px solid #e5e7eb;
1277
1301
  }
1278
1302
 
1279
- /*.btn {
1303
+ .btn-primary-req {
1304
+ background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
1305
+ color: white;
1306
+ box-shadow: 0 4px 15px rgba(30, 64, 175, 0.3);
1280
1307
  padding: 12px 25px;
1281
1308
  border: none;
1282
1309
  border-radius: 10px;
@@ -1284,20 +1311,18 @@ export default {
1284
1311
  font-weight: 600;
1285
1312
  cursor: pointer;
1286
1313
  transition: all 0.3s ease;
1287
- min-width: 120px;
1288
- }*/
1289
-
1290
- .btn-primary-req {
1291
- background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
1292
- color: white;
1293
- box-shadow: 0 4px 15px rgba(30, 64, 175, 0.3);
1294
1314
  }
1295
1315
 
1296
- .btn-primary-req:hover {
1316
+ .btn-primary-req:hover:not(:disabled) {
1297
1317
  transform: translateY(-2px);
1298
1318
  box-shadow: 0 6px 20px rgba(30, 64, 175, 0.4);
1299
1319
  }
1300
1320
 
1321
+ .btn-primary-req:disabled {
1322
+ opacity: 0.6;
1323
+ cursor: not-allowed;
1324
+ }
1325
+
1301
1326
  .btn-secondary {
1302
1327
  background: #6b7280;
1303
1328
  color: white;
@@ -1597,6 +1622,11 @@ export default {
1597
1622
  margin-right: 5px;
1598
1623
  }
1599
1624
 
1625
+ .save-btn:disabled {
1626
+ background: #95a5a6;
1627
+ cursor: not-allowed;
1628
+ }
1629
+
1600
1630
  .cancel-btn {
1601
1631
  background: #e74c3c;
1602
1632
  color: white;
@@ -13,7 +13,7 @@ export const defaultMenuItems = [
13
13
  {
14
14
  type: 'link',
15
15
  label: 'Home',
16
- icon: 'bi bi-speedometer2',
16
+ icon: 'bi bi-house',
17
17
  roles: ['owner', 'staff', 'captain'],
18
18
  href: '/app/dashboard',
19
19
  active: true
@@ -23,22 +23,21 @@ export const defaultMenuItems = [
23
23
  label: 'Guide',
24
24
  icon: 'bi bi-compass',
25
25
  action: 'guide',
26
- // roles: ['crew']
27
-
26
+ roles: ['crew']
28
27
  },
29
28
  {
30
29
  type: 'link',
31
30
  label: 'Activity Log',
32
31
  icon: 'bi bi-activity',
33
32
  href: '/activity-log',
34
- roles: ['owner'] // Role-based visibility
33
+ roles: ['owner']
35
34
  },
36
35
  {
37
36
  type: 'link',
38
37
  label: 'People Manager',
39
38
  icon: 'bi bi-person-plus',
40
39
  href: '/app/people-manager',
41
- roles: ['owner'] // Role-based visibility
40
+ roles: ['owner']
42
41
  },
43
42
  {
44
43
  type: 'text',
@@ -49,28 +48,51 @@ export const defaultMenuItems = [
49
48
  label: 'Compliance',
50
49
  roles: ['owner', 'staff', 'captain'],
51
50
  icon: 'bi bi-list-ul',
51
+ children: [
52
+ { label: 'Vessel Certification', action: 'vessel-cert' },
53
+ { label: 'Reports', action: 'reports' },
54
+ { label: 'Crew Certification', action: 'crew-cert' },
55
+ { label: 'QHSE Compliance', action: 'qhse' },
56
+ { label: 'Track Garbage', action: 'garbage' },
57
+ ]
58
+ },
59
+ {
60
+ // ── HR MODULE ──────────────────────────────────────────────────────────
61
+ // Clock-in/out is office-only (owner + staff roles).
62
+ // Payroll and appraisal will also cover crew in a later release.
63
+ type: 'dropdown',
64
+ label: 'HR',
65
+ icon: 'bi bi-people-fill',
66
+ roles: ['owner', 'staff'],
52
67
  children: [
53
68
  {
54
- label: 'Vessel Certification',
55
- action: 'vessel-cert',
69
+ label: 'Attendance',
70
+ action: 'hr-attendance',
71
+ roles: ['owner', 'staff'],
56
72
  },
57
73
  {
58
- type: 'separator'
74
+ label: 'Payroll',
75
+ action: 'hr-payroll',
76
+ roles: ['owner', 'staff'],
59
77
  },
60
78
  {
61
- label: 'Reports',
62
- action: 'reports'
79
+ label: 'Appraisals',
80
+ action: 'hr-appraisals',
81
+ roles: ['owner', 'staff'],
82
+ },
83
+ {
84
+ label: 'Leave Management',
85
+ action: 'hr-leave',
86
+ roles: ['owner', 'staff'],
87
+ },
88
+ {
89
+ label: 'Disciplinary Log', // Coming next
90
+ action: 'hr-disciplinary',
91
+ roles: ['owner'],
63
92
  },
64
93
  ]
65
94
  },
66
- /*
67
- {
68
- type: 'link',
69
- label: 'Business Intelligence',
70
- icon: 'bi bi-graph-up-arrow',
71
- href: '/app/analytics'
72
- },
73
- */
95
+ /* ── end HR MODULE ── */
74
96
  {
75
97
  type: 'button',
76
98
  label: 'Maintenance',
@@ -84,26 +106,20 @@ export const defaultMenuItems = [
84
106
  icon: 'bi bi-people',
85
107
  roles: ['owner', 'staff', 'captain'],
86
108
  children: [
87
- {
88
- label: 'All Crew',
89
- action: 'crew-all',
90
- roles: ['owner', 'staff']
91
- },
92
- {
93
- type: 'separator'
94
- },
95
- {
96
- label: 'Get Crew by Vessel',
97
- action: 'crew-by-vessel'
98
- }
109
+ { label: 'All Crew', action: 'crew-all', roles: ['owner', 'staff'] },
110
+ { label: 'Get Crew by Vessel', action: 'crew-by-vessel' },
111
+ { label: 'Schedule', action: 'schedule' },
99
112
  ]
100
113
  },
101
114
  {
102
- type: 'link',
115
+ type: 'dropdown',
103
116
  label: 'Inventory Management',
104
117
  icon: 'bi bi-clipboard-data',
105
- href: '/app/inventory',
106
- roles: ['owner', 'staff', 'captain']
118
+ roles: ['owner', 'staff', 'captain'],
119
+ children: [
120
+ { label: 'Parts Inventory', action: 'inventory', roles: ['owner', 'staff', 'captain'] },
121
+ { label: 'Bunkering', action: 'fuel', roles: ['owner', 'staff', 'captain'] },
122
+ ]
107
123
  },
108
124
  {
109
125
  type: 'link',
@@ -118,36 +134,34 @@ export const defaultMenuItems = [
118
134
  icon: 'fas fa-ship',
119
135
  action: 'coming-soon',
120
136
  roles: ['owner', 'staff', 'captain']
121
-
122
137
  },
123
138
  {
124
139
  type: 'button',
125
140
  label: 'Vessel Log',
126
141
  icon: 'bi bi-file-ruled',
127
- action: 'vessel-log',
142
+ action: 'coming-soon',
128
143
  roles: ['owner', 'staff', 'captain']
129
144
  },
130
- {
131
- type: 'button',
132
- label: 'Settings',
133
- icon: 'bi bi-gear',
134
- action: 'settings',
135
- roles: ['owner', 'staff']
136
- },
137
145
  {
138
146
  type: 'button',
139
147
  label: 'Profile',
140
148
  icon: 'bi bi-people',
141
149
  action: 'crew-profile',
142
- // roles: ['crew']
143
-
150
+ roles: ['crew']
151
+ },
152
+ {
153
+ type: 'button',
154
+ label: 'Training',
155
+ icon: 'bi bi-book',
156
+ action: 'crew-training',
157
+ roles: ['crew']
144
158
  },
145
159
  {
146
160
  type: 'button',
147
- label: 'Schedule',
148
- icon: 'bi bi-card-checklist',
149
- action: 'schedule',
150
- // roles: ['crew']
161
+ label: 'Settings',
162
+ icon: 'bi bi-gear',
163
+ action: 'settings',
164
+ roles: ['owner', 'staff']
151
165
  },
152
166
  {
153
167
  type: 'button',