@htlkg/components 0.0.1 → 0.0.2
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.
- package/dist/composables/index.js +206 -19
- package/dist/composables/index.js.map +1 -1
- package/package.json +40 -40
- package/src/composables/__test-useTable__.ts +34 -0
- package/src/composables/index.ts +1 -1
- package/src/composables/useTable.md +350 -0
- package/src/composables/useTable.ts +328 -27
- package/src/data/Table.demo.vue +26 -10
- package/src/data/Table.vue +13 -39
- package/src/forms/JsonSchemaForm.test.ts +98 -168
- package/src/forms/JsonSchemaForm.unit.test.ts +97 -45
- package/src/forms/JsonSchemaForm.vue +17 -1
- package/src/index.ts +3 -0
- package/src/navigation/AdminWrapper.vue +198 -0
- package/src/navigation/Tabs.test.ts +55 -27
- package/src/navigation/index.ts +1 -0
- package/src/overlays/Alert.test.ts +39 -74
- package/src/overlays/Drawer.test.ts +57 -23
- package/src/overlays/Modal.test.ts +54 -42
- package/src/stores/index.ts +7 -0
- package/src/stores/user.ts +33 -0
- package/src/test-setup.ts +235 -0
|
@@ -1,5 +1,59 @@
|
|
|
1
|
-
import { describe, it, expect,
|
|
2
|
-
import {
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { shallowMount } from '@vue/test-utils';
|
|
3
|
+
import { h, defineComponent } from 'vue';
|
|
4
|
+
|
|
5
|
+
// Mock the @hotelinking/ui module
|
|
6
|
+
vi.mock('@hotelinking/ui', () => ({
|
|
7
|
+
uiInput: defineComponent({
|
|
8
|
+
name: 'uiInput',
|
|
9
|
+
props: ['name', 'label', 'type', 'value', 'placeholder', 'error', 'color', 'loading', 'requiredText', 'min', 'max'],
|
|
10
|
+
emits: ['input-changed'],
|
|
11
|
+
setup(props, { emit }) {
|
|
12
|
+
return () => h('div', { class: 'ui-input' });
|
|
13
|
+
}
|
|
14
|
+
}),
|
|
15
|
+
uiSelect: defineComponent({
|
|
16
|
+
name: 'uiSelect',
|
|
17
|
+
props: ['label', 'items', 'select', 'placeholder', 'error', 'color', 'loading', 'requiredText'],
|
|
18
|
+
emits: ['select-changed'],
|
|
19
|
+
setup() {
|
|
20
|
+
return () => h('div', { class: 'ui-select' });
|
|
21
|
+
}
|
|
22
|
+
}),
|
|
23
|
+
uiToggle: defineComponent({
|
|
24
|
+
name: 'uiToggle',
|
|
25
|
+
props: ['item', 'checked', 'loading'],
|
|
26
|
+
emits: ['toggle-changed'],
|
|
27
|
+
setup() {
|
|
28
|
+
return () => h('div', { class: 'ui-toggle' });
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
uiTextArea: defineComponent({
|
|
32
|
+
name: 'uiTextArea',
|
|
33
|
+
props: ['name', 'label', 'value', 'placeholder', 'error', 'color', 'loading', 'requiredText', 'rows'],
|
|
34
|
+
emits: ['input-changed'],
|
|
35
|
+
setup() {
|
|
36
|
+
return () => h('div', { class: 'ui-textarea' });
|
|
37
|
+
}
|
|
38
|
+
}),
|
|
39
|
+
uiRangeSlider: defineComponent({
|
|
40
|
+
name: 'uiRangeSlider',
|
|
41
|
+
props: ['label', 'min', 'max', 'sliderValue', 'loading', 'requiredText'],
|
|
42
|
+
emits: ['sliderUpdated'],
|
|
43
|
+
setup() {
|
|
44
|
+
return () => h('div', { class: 'ui-slider' });
|
|
45
|
+
}
|
|
46
|
+
}),
|
|
47
|
+
uiButton: defineComponent({
|
|
48
|
+
name: 'uiButton',
|
|
49
|
+
props: ['type', 'color', 'loading', 'disabled'],
|
|
50
|
+
setup(props, { slots }) {
|
|
51
|
+
return () => h('button', { class: 'ui-button', type: props.type }, slots.default?.());
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
// Import after mocking
|
|
3
57
|
import JsonSchemaForm from './JsonSchemaForm.vue';
|
|
4
58
|
|
|
5
59
|
/**
|
|
@@ -16,7 +70,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
16
70
|
}
|
|
17
71
|
};
|
|
18
72
|
|
|
19
|
-
const wrapper =
|
|
73
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
20
74
|
props: { schema, modelValue: {} }
|
|
21
75
|
});
|
|
22
76
|
|
|
@@ -32,7 +86,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
32
86
|
}
|
|
33
87
|
};
|
|
34
88
|
|
|
35
|
-
const wrapper =
|
|
89
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
36
90
|
props: { schema, modelValue: {} }
|
|
37
91
|
});
|
|
38
92
|
|
|
@@ -46,7 +100,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
46
100
|
properties: {}
|
|
47
101
|
};
|
|
48
102
|
|
|
49
|
-
const wrapper =
|
|
103
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
50
104
|
props: { schema, modelValue: {} }
|
|
51
105
|
});
|
|
52
106
|
|
|
@@ -67,7 +121,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
67
121
|
}
|
|
68
122
|
};
|
|
69
123
|
|
|
70
|
-
const wrapper =
|
|
124
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
71
125
|
props: { schema, modelValue: {} }
|
|
72
126
|
});
|
|
73
127
|
|
|
@@ -83,7 +137,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
83
137
|
}
|
|
84
138
|
};
|
|
85
139
|
|
|
86
|
-
const wrapper =
|
|
140
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
87
141
|
props: { schema, modelValue: {} }
|
|
88
142
|
});
|
|
89
143
|
|
|
@@ -102,7 +156,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
102
156
|
required: ['email']
|
|
103
157
|
};
|
|
104
158
|
|
|
105
|
-
const wrapper =
|
|
159
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
106
160
|
props: { schema, modelValue: {} }
|
|
107
161
|
});
|
|
108
162
|
|
|
@@ -119,7 +173,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
119
173
|
required: []
|
|
120
174
|
};
|
|
121
175
|
|
|
122
|
-
const wrapper =
|
|
176
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
123
177
|
props: { schema, modelValue: {} }
|
|
124
178
|
});
|
|
125
179
|
|
|
@@ -135,7 +189,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
135
189
|
}
|
|
136
190
|
};
|
|
137
191
|
|
|
138
|
-
const wrapper =
|
|
192
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
139
193
|
props: { schema, modelValue: {} }
|
|
140
194
|
});
|
|
141
195
|
|
|
@@ -157,7 +211,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
157
211
|
password: { 'ui:widget': 'password' }
|
|
158
212
|
};
|
|
159
213
|
|
|
160
|
-
const wrapper =
|
|
214
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
161
215
|
props: { schema, uiSchema, modelValue: {} }
|
|
162
216
|
});
|
|
163
217
|
|
|
@@ -173,7 +227,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
173
227
|
}
|
|
174
228
|
};
|
|
175
229
|
|
|
176
|
-
const wrapper =
|
|
230
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
177
231
|
props: { schema, modelValue: {} }
|
|
178
232
|
});
|
|
179
233
|
|
|
@@ -189,7 +243,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
189
243
|
}
|
|
190
244
|
};
|
|
191
245
|
|
|
192
|
-
const wrapper =
|
|
246
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
193
247
|
props: { schema, modelValue: {} }
|
|
194
248
|
});
|
|
195
249
|
|
|
@@ -205,7 +259,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
205
259
|
}
|
|
206
260
|
};
|
|
207
261
|
|
|
208
|
-
const wrapper =
|
|
262
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
209
263
|
props: { schema, modelValue: {} }
|
|
210
264
|
});
|
|
211
265
|
|
|
@@ -222,7 +276,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
222
276
|
}
|
|
223
277
|
};
|
|
224
278
|
|
|
225
|
-
const wrapper =
|
|
279
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
226
280
|
props: { schema, modelValue: {} }
|
|
227
281
|
});
|
|
228
282
|
|
|
@@ -238,7 +292,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
238
292
|
}
|
|
239
293
|
};
|
|
240
294
|
|
|
241
|
-
const wrapper =
|
|
295
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
242
296
|
props: { schema, modelValue: {} }
|
|
243
297
|
});
|
|
244
298
|
|
|
@@ -254,7 +308,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
254
308
|
}
|
|
255
309
|
};
|
|
256
310
|
|
|
257
|
-
const wrapper =
|
|
311
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
258
312
|
props: { schema, modelValue: {} }
|
|
259
313
|
});
|
|
260
314
|
|
|
@@ -270,7 +324,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
270
324
|
}
|
|
271
325
|
};
|
|
272
326
|
|
|
273
|
-
const wrapper =
|
|
327
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
274
328
|
props: { schema, modelValue: {} }
|
|
275
329
|
});
|
|
276
330
|
|
|
@@ -286,7 +340,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
286
340
|
}
|
|
287
341
|
};
|
|
288
342
|
|
|
289
|
-
const wrapper =
|
|
343
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
290
344
|
props: { schema, modelValue: {} }
|
|
291
345
|
});
|
|
292
346
|
|
|
@@ -308,7 +362,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
308
362
|
pwd: { 'ui:widget': 'password' }
|
|
309
363
|
};
|
|
310
364
|
|
|
311
|
-
const wrapper =
|
|
365
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
312
366
|
props: { schema, uiSchema, modelValue: {} }
|
|
313
367
|
});
|
|
314
368
|
|
|
@@ -324,7 +378,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
324
378
|
}
|
|
325
379
|
};
|
|
326
380
|
|
|
327
|
-
const wrapper =
|
|
381
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
328
382
|
props: { schema, modelValue: {} }
|
|
329
383
|
});
|
|
330
384
|
|
|
@@ -340,7 +394,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
340
394
|
}
|
|
341
395
|
};
|
|
342
396
|
|
|
343
|
-
const wrapper =
|
|
397
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
344
398
|
props: { schema, modelValue: {} }
|
|
345
399
|
});
|
|
346
400
|
|
|
@@ -356,7 +410,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
356
410
|
}
|
|
357
411
|
};
|
|
358
412
|
|
|
359
|
-
const wrapper =
|
|
413
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
360
414
|
props: { schema, modelValue: {} }
|
|
361
415
|
});
|
|
362
416
|
|
|
@@ -374,7 +428,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
374
428
|
}
|
|
375
429
|
};
|
|
376
430
|
|
|
377
|
-
const wrapper =
|
|
431
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
378
432
|
props: { schema, modelValue: {} }
|
|
379
433
|
});
|
|
380
434
|
|
|
@@ -391,7 +445,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
391
445
|
required: ['email']
|
|
392
446
|
};
|
|
393
447
|
|
|
394
|
-
const wrapper =
|
|
448
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
395
449
|
props: { schema, modelValue: { email: 'invalid' } }
|
|
396
450
|
});
|
|
397
451
|
|
|
@@ -413,7 +467,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
413
467
|
required: ['name']
|
|
414
468
|
};
|
|
415
469
|
|
|
416
|
-
const wrapper =
|
|
470
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
417
471
|
props: { schema, modelValue: { name: 'John' } }
|
|
418
472
|
});
|
|
419
473
|
|
|
@@ -433,7 +487,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
433
487
|
}
|
|
434
488
|
};
|
|
435
489
|
|
|
436
|
-
const wrapper =
|
|
490
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
437
491
|
props: { schema, modelValue: {} }
|
|
438
492
|
});
|
|
439
493
|
|
|
@@ -457,7 +511,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
457
511
|
email: { 'ui:placeholder': 'Enter your email' }
|
|
458
512
|
};
|
|
459
513
|
|
|
460
|
-
const wrapper =
|
|
514
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
461
515
|
props: { schema, uiSchema, modelValue: {} }
|
|
462
516
|
});
|
|
463
517
|
|
|
@@ -473,7 +527,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
473
527
|
}
|
|
474
528
|
};
|
|
475
529
|
|
|
476
|
-
const wrapper =
|
|
530
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
477
531
|
props: { schema, modelValue: {} }
|
|
478
532
|
});
|
|
479
533
|
|
|
@@ -494,7 +548,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
494
548
|
}
|
|
495
549
|
};
|
|
496
550
|
|
|
497
|
-
const wrapper =
|
|
551
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
498
552
|
props: { schema, modelValue: {} }
|
|
499
553
|
});
|
|
500
554
|
|
|
@@ -503,8 +557,6 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
503
557
|
|
|
504
558
|
expect(options).toHaveLength(3);
|
|
505
559
|
expect(options[0]).toEqual({ id: 'active', name: 'active', label: 'active' });
|
|
506
|
-
expect(options[1]).toEqual({ id: 'inactive', name: 'inactive', label: 'inactive' });
|
|
507
|
-
expect(options[2]).toEqual({ id: 'pending', name: 'pending', label: 'pending' });
|
|
508
560
|
});
|
|
509
561
|
|
|
510
562
|
it('should return empty array when enum is not defined', () => {
|
|
@@ -515,7 +567,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
515
567
|
}
|
|
516
568
|
};
|
|
517
569
|
|
|
518
|
-
const wrapper =
|
|
570
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
519
571
|
props: { schema, modelValue: {} }
|
|
520
572
|
});
|
|
521
573
|
|
|
@@ -531,7 +583,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
531
583
|
}
|
|
532
584
|
};
|
|
533
585
|
|
|
534
|
-
const wrapper =
|
|
586
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
535
587
|
props: { schema, modelValue: {} }
|
|
536
588
|
});
|
|
537
589
|
|
|
@@ -552,7 +604,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
552
604
|
}
|
|
553
605
|
};
|
|
554
606
|
|
|
555
|
-
const wrapper =
|
|
607
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
556
608
|
props: {
|
|
557
609
|
schema,
|
|
558
610
|
modelValue: { status: 'active' }
|
|
@@ -573,7 +625,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
573
625
|
}
|
|
574
626
|
};
|
|
575
627
|
|
|
576
|
-
const wrapper =
|
|
628
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
577
629
|
props: { schema, modelValue: {} }
|
|
578
630
|
});
|
|
579
631
|
|
|
@@ -593,7 +645,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
593
645
|
}
|
|
594
646
|
};
|
|
595
647
|
|
|
596
|
-
const wrapper =
|
|
648
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
597
649
|
props: { schema, modelValue: {} }
|
|
598
650
|
});
|
|
599
651
|
|
|
@@ -614,7 +666,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
614
666
|
}
|
|
615
667
|
};
|
|
616
668
|
|
|
617
|
-
const wrapper =
|
|
669
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
618
670
|
props: { schema, modelValue: {} }
|
|
619
671
|
});
|
|
620
672
|
|
|
@@ -638,7 +690,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
638
690
|
required: ['email']
|
|
639
691
|
};
|
|
640
692
|
|
|
641
|
-
const wrapper =
|
|
693
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
642
694
|
props: { schema, modelValue: {} }
|
|
643
695
|
});
|
|
644
696
|
|
|
@@ -662,7 +714,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
662
714
|
required: ['name']
|
|
663
715
|
};
|
|
664
716
|
|
|
665
|
-
const wrapper =
|
|
717
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
666
718
|
props: {
|
|
667
719
|
schema,
|
|
668
720
|
modelValue: { name: 'John' }
|
|
@@ -684,7 +736,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
684
736
|
required: ['email']
|
|
685
737
|
};
|
|
686
738
|
|
|
687
|
-
const wrapper =
|
|
739
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
688
740
|
props: {
|
|
689
741
|
schema,
|
|
690
742
|
modelValue: { email: 'invalid' }
|
|
@@ -708,7 +760,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
708
760
|
required: ['name']
|
|
709
761
|
};
|
|
710
762
|
|
|
711
|
-
const wrapper =
|
|
763
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
712
764
|
props: { schema, modelValue: {} }
|
|
713
765
|
});
|
|
714
766
|
|
|
@@ -729,7 +781,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
729
781
|
}
|
|
730
782
|
};
|
|
731
783
|
|
|
732
|
-
const wrapper =
|
|
784
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
733
785
|
props: {
|
|
734
786
|
schema,
|
|
735
787
|
modelValue: { name: 'John' }
|
|
@@ -758,7 +810,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
758
810
|
required: ['email']
|
|
759
811
|
};
|
|
760
812
|
|
|
761
|
-
const wrapper =
|
|
813
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
762
814
|
props: { schema, modelValue: {} }
|
|
763
815
|
});
|
|
764
816
|
|
|
@@ -782,7 +834,7 @@ describe('JsonSchemaForm unit tests', () => {
|
|
|
782
834
|
}
|
|
783
835
|
};
|
|
784
836
|
|
|
785
|
-
const wrapper =
|
|
837
|
+
const wrapper = shallowMount(JsonSchemaForm, {
|
|
786
838
|
props: { schema, modelValue: {} }
|
|
787
839
|
});
|
|
788
840
|
|
|
@@ -395,11 +395,27 @@ function updateArrayItem(fieldName: string, index: number, value: any) {
|
|
|
395
395
|
// Expose methods
|
|
396
396
|
defineExpose({
|
|
397
397
|
validate,
|
|
398
|
+
validateField,
|
|
398
399
|
reset: () => {
|
|
399
400
|
emit('update:modelValue', {});
|
|
400
401
|
errors.value = {};
|
|
401
402
|
touched.value = {};
|
|
402
|
-
}
|
|
403
|
+
},
|
|
404
|
+
// Expose internal state for testing
|
|
405
|
+
formData,
|
|
406
|
+
errors,
|
|
407
|
+
touched,
|
|
408
|
+
// Expose helper methods for testing
|
|
409
|
+
getFieldLabel,
|
|
410
|
+
getFieldDescription,
|
|
411
|
+
isRequired,
|
|
412
|
+
getWidget,
|
|
413
|
+
getInputType,
|
|
414
|
+
getFieldColor,
|
|
415
|
+
getPlaceholder,
|
|
416
|
+
getSelectOptions,
|
|
417
|
+
getSelectedOption,
|
|
418
|
+
updateField
|
|
403
419
|
});
|
|
404
420
|
</script>
|
|
405
421
|
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Wrapper Component
|
|
3
|
+
*
|
|
4
|
+
* Wraps uiWrapper from @hotelinking/ui with sidebar, topbar, and content area.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<uiWrapper
|
|
9
|
+
:sidebar="sidebarConfig as any"
|
|
10
|
+
:topbar="topbarConfig as any"
|
|
11
|
+
:sidebarOpen="sidebarOpen"
|
|
12
|
+
@selectChanged="handleSelectChanged"
|
|
13
|
+
@topBarClick="handleTopBarClick"
|
|
14
|
+
@sideBarClick="handleSideBarClick"
|
|
15
|
+
@productBarClick="handleProductBarClick"
|
|
16
|
+
@inputChanged="handleInputChanged"
|
|
17
|
+
@sidebarToggle="(isOpen: boolean) => sidebarOpen = isOpen"
|
|
18
|
+
>
|
|
19
|
+
<slot></slot>
|
|
20
|
+
</uiWrapper>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup lang="ts">
|
|
24
|
+
import type { SelectItemType } from "@hotelinking/ui";
|
|
25
|
+
import { uiWrapper } from "@hotelinking/ui";
|
|
26
|
+
import { useStore } from "@nanostores/vue";
|
|
27
|
+
import { computed, ref } from "vue";
|
|
28
|
+
import { $user } from "../stores/user";
|
|
29
|
+
|
|
30
|
+
// Props interface (user is now from nanostore)
|
|
31
|
+
interface Props {
|
|
32
|
+
sidebarLogo: string;
|
|
33
|
+
currentPage?: string;
|
|
34
|
+
sidebarTitle?: string;
|
|
35
|
+
sidebarItems?: Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
icon?: string;
|
|
38
|
+
id: string;
|
|
39
|
+
routeName: string;
|
|
40
|
+
}>;
|
|
41
|
+
topbarActions?: Array<{
|
|
42
|
+
name: string;
|
|
43
|
+
event: string;
|
|
44
|
+
icon: string;
|
|
45
|
+
}>;
|
|
46
|
+
selectItems?: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
id: string;
|
|
49
|
+
}>;
|
|
50
|
+
selectedItem?: {
|
|
51
|
+
name: string;
|
|
52
|
+
id: string;
|
|
53
|
+
};
|
|
54
|
+
productsSidebar?: Array<{
|
|
55
|
+
name: string;
|
|
56
|
+
icon: string;
|
|
57
|
+
active?: boolean;
|
|
58
|
+
}>;
|
|
59
|
+
sidebarOpenByDefault?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
63
|
+
currentPage: "dashboard",
|
|
64
|
+
sidebarItems: () => [],
|
|
65
|
+
topbarActions: () => [],
|
|
66
|
+
selectItems: () => [],
|
|
67
|
+
selectedItem: () => ({ name: "", id: "" }),
|
|
68
|
+
productsSidebar: () => [],
|
|
69
|
+
sidebarOpenByDefault: true,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Emit events
|
|
73
|
+
const emit = defineEmits<{
|
|
74
|
+
selectChanged: [item: { name: string; id: string }];
|
|
75
|
+
}>();
|
|
76
|
+
|
|
77
|
+
// Reactive state
|
|
78
|
+
const sidebarOpen = ref(props.sidebarOpenByDefault);
|
|
79
|
+
|
|
80
|
+
// Get user from nanostore (no props needed!)
|
|
81
|
+
const user = useStore($user);
|
|
82
|
+
|
|
83
|
+
// Computed properties for UI configuration
|
|
84
|
+
const topbarConfig = computed(() => {
|
|
85
|
+
return {
|
|
86
|
+
logo: props.sidebarLogo,
|
|
87
|
+
accountLogo: user.value?.avatar || "",
|
|
88
|
+
alerted: false,
|
|
89
|
+
profileMenu: [
|
|
90
|
+
{
|
|
91
|
+
name: "Profile",
|
|
92
|
+
id: "profile",
|
|
93
|
+
href: "/profile",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "Settings",
|
|
97
|
+
id: "settings",
|
|
98
|
+
href: "/settings",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "Logout",
|
|
102
|
+
id: "logout",
|
|
103
|
+
href: "#",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
brand: {
|
|
107
|
+
name: user.value?.username || "User",
|
|
108
|
+
description: user.value?.email || "",
|
|
109
|
+
},
|
|
110
|
+
selectItems: props.selectItems,
|
|
111
|
+
selectedItem: props.selectedItem,
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const sidebarConfig = computed(() => {
|
|
116
|
+
// Add current attribute dynamically based on currentPage
|
|
117
|
+
const navigationItems = props.sidebarItems.map((item) => ({
|
|
118
|
+
name: item.name,
|
|
119
|
+
icon: item.icon,
|
|
120
|
+
id: item.id,
|
|
121
|
+
current: item.id === props.currentPage,
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
navigation: navigationItems,
|
|
126
|
+
productsSidebar: props.productsSidebar,
|
|
127
|
+
logo: props.sidebarLogo,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Event handlers
|
|
132
|
+
const handleSelectChanged = (item: SelectItemType | SelectItemType[]) => {
|
|
133
|
+
console.log("Select changed:", item);
|
|
134
|
+
// Emit to parent component
|
|
135
|
+
if (!Array.isArray(item) && item.id) {
|
|
136
|
+
emit("selectChanged", { name: item.name, id: item.id });
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const handleTopBarClick = (event: unknown) => {
|
|
141
|
+
// Handle different possible event formats
|
|
142
|
+
let menuItem: string | undefined;
|
|
143
|
+
|
|
144
|
+
if (typeof event === "string") {
|
|
145
|
+
menuItem = event;
|
|
146
|
+
} else if (event && typeof event === "object") {
|
|
147
|
+
// Check if it's an object with name or href property
|
|
148
|
+
const eventObj = event as Record<string, unknown>;
|
|
149
|
+
menuItem = (eventObj.name as string) || (eventObj.href as string);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log("Extracted menu item:", menuItem);
|
|
153
|
+
|
|
154
|
+
// The event is the menu item name
|
|
155
|
+
if (menuItem === "logout") {
|
|
156
|
+
handleLogout();
|
|
157
|
+
} else if (menuItem === "profile") {
|
|
158
|
+
window.location.href = "/profile";
|
|
159
|
+
} else if (menuItem === "settings") {
|
|
160
|
+
window.location.href = "/settings";
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const handleSideBarClick = (itemId: string) => {
|
|
165
|
+
console.log("Sidebar click:", itemId);
|
|
166
|
+
|
|
167
|
+
// Find the item by id to get the routeName
|
|
168
|
+
const item = props.sidebarItems.find(
|
|
169
|
+
(i) => (i.id || i.name.toLowerCase()) === itemId,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (item?.routeName) {
|
|
173
|
+
window.location.href = item.routeName;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const handleProductBarClick = (event: unknown) => {
|
|
178
|
+
console.log("Product bar click:", event);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const handleInputChanged = (event: unknown) => {
|
|
182
|
+
console.log("Input changed:", event);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const handleLogout = async () => {
|
|
186
|
+
try {
|
|
187
|
+
// Import logout from auth package
|
|
188
|
+
const { signOut } = await import('@htlkg/core/auth');
|
|
189
|
+
await signOut();
|
|
190
|
+
// Redirect to login page
|
|
191
|
+
window.location.href = "/login";
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error("Logout error:", error);
|
|
194
|
+
// Force redirect even if logout fails
|
|
195
|
+
window.location.href = "/login";
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
</script>
|