bt-core-app 1.1.9 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/bt-core-app.js +25270 -15306
  2. package/dist/components/BT-Btn.vue.d.ts +41 -0
  3. package/dist/components/BT-Col.vue.d.ts +49 -0
  4. package/dist/components/BT-Field-Checkbox.vue.d.ts +56 -0
  5. package/dist/components/BT-Field-Date.vue.d.ts +64 -0
  6. package/dist/components/BT-Field-Entity.vue.d.ts +46 -0
  7. package/dist/components/BT-Field-Select.vue.d.ts +54 -0
  8. package/dist/components/BT-Field-String.vue.d.ts +53 -0
  9. package/dist/components/BT-Field-Switch.vue.d.ts +51 -0
  10. package/dist/components/BT-Field-Tags.vue.d.ts +51 -0
  11. package/dist/components/BT-Field-Textarea.vue.d.ts +52 -0
  12. package/dist/components/BT-Field-Trigger.vue.d.ts +79 -0
  13. package/dist/components/BT-Header-Option.vue.d.ts +18 -0
  14. package/dist/components/BT-Json.vue.d.ts +8 -0
  15. package/dist/components/BT-Select-List-Box.vue.d.ts +108 -0
  16. package/dist/components/BT-Select.vue.d.ts +53 -0
  17. package/dist/components/BT-Snack.vue.d.ts +33 -0
  18. package/dist/components/Dialog-Confirm.vue.d.ts +2 -2
  19. package/dist/components/Dialog-Select-Date.vue.d.ts +2 -2
  20. package/dist/components/Dialog-Select.vue.d.ts +2 -2
  21. package/dist/components/Dialog-Text.vue.d.ts +2 -2
  22. package/dist/composables/actions.d.ts +6 -6
  23. package/dist/composables/api.d.ts +1 -0
  24. package/dist/composables/auth.d.ts +1 -0
  25. package/dist/composables/cosmetics.d.ts +3 -1
  26. package/dist/composables/dates.d.ts +1 -0
  27. package/dist/composables/demo.d.ts +1 -0
  28. package/dist/composables/filters.d.ts +1 -0
  29. package/dist/composables/list.d.ts +11 -2
  30. package/dist/composables/navigation.d.ts +1 -0
  31. package/dist/composables/presets.d.ts +1 -0
  32. package/dist/composables/pwa.d.ts +1 -0
  33. package/dist/composables/stores.d.ts +17 -6
  34. package/dist/index.d.ts +11 -12
  35. package/dist/style.css +1 -1
  36. package/dist/types.d.ts +2 -0
  37. package/dist/useApi.d.ts +0 -30
  38. package/package.json +2 -1
  39. package/src/components/BT-Btn.vue +1 -1
  40. package/src/components/BT-Field-Checkbox.vue +70 -0
  41. package/src/components/BT-Field-Date.vue +108 -0
  42. package/src/components/BT-Field-Entity.vue +48 -0
  43. package/src/components/BT-Field-Select.vue +67 -0
  44. package/src/components/BT-Field-String.vue +78 -0
  45. package/src/components/BT-Field-Switch.vue +68 -0
  46. package/src/components/BT-Field-Tags.vue +66 -0
  47. package/src/components/BT-Field-Textarea.vue +67 -0
  48. package/src/components/BT-Field-Trigger.vue +315 -0
  49. package/src/components/BT-Header-Option.vue +39 -0
  50. package/src/components/BT-Json.vue +67 -0
  51. package/src/components/BT-Select-List-Box.vue +258 -0
  52. package/src/components/BT-Select.vue +46 -0
  53. package/src/components/BT-Snack.vue +31 -0
  54. package/src/components/Dialog-Select-Date.vue +1 -1
  55. package/src/composables/actions.ts +6 -6
  56. package/src/composables/api.ts +9 -1
  57. package/src/composables/auth.ts +15 -21
  58. package/src/composables/cosmetics.ts +27 -28
  59. package/src/composables/dates.ts +9 -1
  60. package/src/composables/demo.ts +9 -1
  61. package/src/composables/filters.ts +9 -1
  62. package/src/composables/list.ts +5 -2
  63. package/src/composables/navigation.ts +9 -1
  64. package/src/composables/presets.ts +9 -1
  65. package/src/composables/pwa.ts +9 -1
  66. package/src/composables/stores.ts +32 -11
  67. package/src/core.ts +49 -16
  68. package/src/index.ts +12 -12
  69. package/src/types.ts +5 -1
  70. package/src/useApi.ts +57 -57
  71. package/test/auth.test.ts +63 -0
  72. package/test/stores-last-update.test.ts +4 -4
  73. package/vite.config.ts +6 -2
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <v-slide-x-transition group>
3
+ <span v-if="option.prefix != null">{{ option.prefix }}</span>
4
+ <span v-if="option.bool != null">
5
+ <v-icon v-if="nestedValue(data, option.value) === true" :size="size">mdi-check</v-icon>
6
+ </span>
7
+ <bt-entity
8
+ v-else-if="option.nav != null && (option.itemText != null || option.textFilter != null)"
9
+ inline
10
+ :itemText="option.itemText"
11
+ :itemId="nestedValue(data, option.value)"
12
+ :nav="option.nav"
13
+ :single="option.single"
14
+ :textFilter="option.textFilter" />
15
+ <span v-else>{{ displayText(data) }}</span>
16
+ </v-slide-x-transition>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { type TableColumn } from '../composables/list'
21
+ import { nestedValue } from '../composables/helpers'
22
+ import { useFilters } from '../composables/filters'
23
+ import { computed } from 'vue';
24
+
25
+ interface Props {
26
+ data: any
27
+ option: TableColumn
28
+ size?: string | number
29
+ }
30
+
31
+ const props = defineProps<Props>()
32
+ const filters = useFilters()
33
+ const displayText = computed(() => (item: any) => {
34
+ let v = nestedValue(item, props.option.value)
35
+ v = props.option.textFunction != null ? props.option.textFunction(v) : v
36
+ return props.option.textFilter != null ? filters.findFilter(props.option.textFilter)(v) : v
37
+ })
38
+
39
+ </script>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <v-card max-height="350" class="overflow-y-auto">
3
+ <v-card-text>
4
+ <div v-for="(j, ind) in display" :key="ind">
5
+ <pre v-html="syntaxHighlight(j)"></pre>
6
+ </div>
7
+ </v-card-text>
8
+ </v-card>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import { computed } from 'vue'
13
+
14
+ const props = defineProps(['value'])
15
+
16
+ const display = computed(() => {
17
+ if (props.value == null) {
18
+ return []
19
+ }
20
+
21
+ if (Array.isArray(props.value))
22
+ return props.value
23
+
24
+ return [props.value]
25
+ })
26
+
27
+ function syntaxHighlight(json: any) {
28
+ if (typeof json != 'string') {
29
+ json = JSON.stringify(json, undefined, 2); //Object.keys(json).sort(), 2);
30
+ }
31
+ json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
32
+
33
+ const e = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match: any) {
34
+ var cls = 'number';
35
+ if (/^"/.test(match)) {
36
+ if (/:$/.test(match)) {
37
+ cls = 'key';
38
+ } else {
39
+ cls = 'string';
40
+ }
41
+ } else if (/true|false/.test(match)) {
42
+ cls = 'boolean';
43
+ } else if (/null/.test(match)) {
44
+ cls = 'null';
45
+ }
46
+ return '<span class="' + cls + '">' + match + '</span>';
47
+ });
48
+
49
+ return e
50
+ }
51
+
52
+ </script>
53
+
54
+ <style>
55
+ pre {
56
+ outline: 1px solid #ccc;
57
+ padding: 5px;
58
+ margin: 5px; }
59
+
60
+ pre .string {
61
+ color: green;
62
+ }
63
+ pre .number { color: darkorange; }
64
+ pre .boolean { color: rgb(191, 255, 0); }
65
+ pre .null { color: magenta; }
66
+ pre .key { color: rgb(141, 141, 141); }
67
+ </style>
@@ -0,0 +1,258 @@
1
+ <template>
2
+ <v-col
3
+ :class="colClass"
4
+ :lg="mLg"
5
+ :md="mMd"
6
+ :sm="mSm"
7
+ :cols="cols">
8
+ <v-list-item v-if="!alwaysOpen && mIsSelecting" @click="mIsSelecting = false"
9
+ :subtitle="label">
10
+ <template #append>
11
+ <v-row class="ma-0 pa-0">
12
+ <slot name="actions" />
13
+ <v-icon>mdi-chevron-up</v-icon>
14
+ <slot name="actionsRight" />
15
+ <v-menu
16
+ v-if="showSettings"
17
+ offset-y
18
+ :close-on-content-click="false">
19
+ <template v-slot:activator="{ props }">
20
+ <v-btn
21
+ icon="mdi-cog"
22
+ :size="mSize"
23
+ title="Settings"
24
+ v-bind="props" />
25
+ </template>
26
+ <v-list>
27
+ <slot name="settings" />
28
+ </v-list>
29
+ </v-menu>
30
+ </v-row>
31
+ </template>
32
+ </v-list-item>
33
+ <v-slide-y-transition hide-on-leave group>
34
+ <v-text-field
35
+ v-if="(alwaysOpen || mIsSelecting) && showSearch !== false && isLengthyArray(searchProps)"
36
+ @click:prepend-inner="ui.searchString.value = undefined"
37
+ hide-details
38
+ key="1"
39
+ placeholder="Search"
40
+ :prepend-inner-icon="ui.searchString.value != null ? 'mdi-close' : undefined"
41
+ v-model="ui.searchString.value">
42
+ <template #append-inner>
43
+ <v-btn
44
+ v-if="canRefresh"
45
+ @click="ui.refresh({ deepRefresh: true })"
46
+ icon="mdi-refresh"
47
+ :size="mSize"
48
+ variant="text" />
49
+ </template>
50
+
51
+ </v-text-field>
52
+ <v-virtual-scroll
53
+ v-if="(alwaysOpen || mIsSelecting) && useVirtualScroller"
54
+ :height="height"
55
+ :items="ui.filteredItems.value"
56
+ key="2">
57
+ <template #default="{ item }">
58
+ <slot name="item" v-bind:item="item" v-bind:selectItem="selectItem(item)" :active="isActive(item)">
59
+ <v-list-item @click="selectItem(item)" :active="isActive(item)" color="primary">
60
+ <slot v-bind:item="item">
61
+ <v-list-item-title v-if="itemText != null || textFilter != null || textFunction != null">
62
+ {{ displayTitle(item) }}
63
+ </v-list-item-title>
64
+ <v-list-item-subtitle v-if="itemSubtext != null || subtextFilter != null || subtextFunction != null">
65
+ {{ displaySubtitle(item) }}
66
+ </v-list-item-subtitle>
67
+ </slot>
68
+
69
+ </v-list-item>
70
+ </slot>
71
+ </template>
72
+ </v-virtual-scroll>
73
+ <v-list
74
+ v-else-if="alwaysOpen || mIsSelecting"
75
+ :bg-color="transparent ? 'transparent' : undefined"
76
+ :height="height"
77
+ key="3">
78
+ <v-list-item
79
+ v-if="canSelectNone"
80
+ key="-1"
81
+ density="compact"
82
+ @click="selectItem(null)"
83
+ subtitle="(Select None)" />
84
+
85
+ <template v-for="(fItem, fInd) in ui.filteredItems.value">
86
+ <slot name="item" :items="fItem" :index="fInd" :size="mSize">
87
+ <v-list-item
88
+ :active="isActive(fItem)"
89
+ :key="fInd"
90
+ :value="fItem"
91
+ @click="selectItem(fItem)">
92
+ <slot :item="fItem" :index="fInd" :size="mSize">
93
+ <v-list-item-title v-if="itemText != null || textFilter != null || textFunction != null">
94
+ {{ displayTitle(fItem) }}
95
+ </v-list-item-title>
96
+ <v-list-item-subtitle v-if="itemSubtext != null || subtextFilter != null || subtextFunction != null">
97
+ {{ displaySubtitle(fItem) }}
98
+ </v-list-item-subtitle>
99
+ </slot>
100
+ </v-list-item>
101
+ </slot>
102
+ </template>
103
+ </v-list>
104
+ <slot v-else name="selected" :item="selectedItem" :open="openList">
105
+ <v-list-item
106
+ @click="openList"
107
+ key="4"
108
+ :title="label"
109
+ :subtitle="displayTitle(selectedItem) ?? placeholder">
110
+ <template #append>
111
+ <v-row no-gutters>
112
+ <slot name="actions" />
113
+ <v-icon>mdi-chevron-down</v-icon>
114
+ <slot name="actionsRight" />
115
+ <v-menu
116
+ v-if="showSettings"
117
+ offset-y
118
+ :close-on-content-click="false">
119
+ <template v-slot:activator="{ props }">
120
+ <v-btn
121
+ icon
122
+ v-bind="props"
123
+ :size="mSize"
124
+ title="Settings" />
125
+ </template>
126
+ <v-list>
127
+ <slot name="settings" />
128
+ </v-list>
129
+ </v-menu>
130
+ </v-row>
131
+ </template>
132
+ </v-list-item>
133
+ </slot>
134
+
135
+ </v-slide-y-transition>
136
+
137
+ <v-overlay
138
+ v-model="ui.isLoading.value"
139
+ class="align-center justify-center text-center"
140
+ contained
141
+ persistent>
142
+ <v-progress-circular indeterminate />
143
+ <p>{{ ui.loadingMsg.value }}</p>
144
+ </v-overlay>
145
+ </v-col>
146
+
147
+ </template>
148
+
149
+ <script setup lang="ts">
150
+ import { type ListProps, useList } from '../composables/list'
151
+ import { computed, inject, ref } from 'vue'
152
+ import { useFilters } from '../composables/filters'
153
+ import { isLengthyArray, nestedValue } from '../composables/helpers'
154
+
155
+ defineOptions({
156
+ inheritAttrs: false
157
+ })
158
+
159
+ interface SelectProps extends ListProps {
160
+ alwaysOpen?: boolean
161
+ canRefresh?: boolean
162
+ canSearch?: boolean
163
+ canSelectNone?: boolean
164
+ colClass?: string
165
+ cols?: string | boolean
166
+ height?: string
167
+ isMobile?: boolean
168
+ isEditing?: boolean
169
+ isSelecting?: boolean
170
+ items?: [],
171
+ itemSubtext?: string
172
+ itemText?: string
173
+ itemValue?: string //inherited
174
+ label?: string
175
+ lg?: string | boolean
176
+ modelValue?: any
177
+ md?: string | boolean
178
+ nav?: string
179
+ placeholder?: string
180
+ showSettings?: boolean
181
+ sm?: string | boolean
182
+ subtextFilter?: string
183
+ subtextFunction?: Function
184
+ textFilter?: string
185
+ textFunction?: Function
186
+ transparent?: boolean
187
+ useVirtualScroller?: boolean
188
+ }
189
+
190
+ const emit = defineEmits(['update:modelValue', 'change'])
191
+
192
+ const props = withDefaults(defineProps<SelectProps>(), {
193
+ canRefresh: true,
194
+ height: '400',
195
+ isEditing: undefined,
196
+ sortOrder: 'Ascending',
197
+ cols: '12',
198
+ lg: false,
199
+ md: false,
200
+ sm: '6'
201
+ })
202
+
203
+ const mIsSelecting = ref(props.alwaysOpen ?? props.isSelecting ?? false)
204
+ const mSize = inject('size', () => ref('small'), true)
205
+ const mIsEditing = inject('isEditing', () => ref(false), true)
206
+ const cIsEditing = computed(() => props.isEditing ?? mIsEditing.value)
207
+
208
+ const ui = useList(props, undefined, {
209
+ useBladeSrc: false,
210
+ useRouteSrc: false
211
+ })
212
+
213
+ const filters = useFilters()
214
+
215
+ const displaySubtitle = computed(() => (item: any) => {
216
+ let v = props.subtextFunction != null ? props.subtextFunction(item) : item
217
+ v = props.itemSubtext != null ? nestedValue(v, props.itemSubtext) : v
218
+ return props.subtextFilter != null ? filters.findFilter(props.subtextFilter)(v) : v
219
+ })
220
+
221
+ const displayTitle = computed(() => (item: any) => {
222
+ let v = props.textFunction != null ? props.textFunction(item) : item
223
+ v = props.itemText != null ? nestedValue(v, props.itemText) : v
224
+ return props.textFilter != null ? filters.findFilter(props.textFilter)(v) : v
225
+ })
226
+
227
+ const isActive = computed(() => (item: any) => {
228
+ return (props.itemValue ? item[props.itemValue] : item) == props.modelValue
229
+ })
230
+
231
+ function openList() {
232
+ if (cIsEditing.value)
233
+ mIsSelecting.value = true
234
+ }
235
+
236
+ function selectItem(item: any) {
237
+ mIsSelecting.value = false
238
+
239
+ if (item != null || props.canSelectNone) {
240
+ let v = item
241
+
242
+ if (item != null && props.itemValue != null)
243
+ v = item[props.itemValue]
244
+
245
+ emit('update:modelValue', v)
246
+ emit('change', v)
247
+ }
248
+ }
249
+
250
+ const selectedItem = computed(() => {
251
+ return props.modelValue != null ? ui.asyncItems.value.find((x: any) => (x.id == props.modelValue)) : null
252
+ })
253
+
254
+ const mIsMobile = inject('isMobile', () => ref(false), true)
255
+ const mLg = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.lg)
256
+ const mMd = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.md)
257
+ const mSm = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.sm)
258
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <v-select
3
+ :append-icon="canRefresh ? 'mdi-refresh' : undefined"
4
+ :clearable="canSelectNone"
5
+ @click:append-icon="ui.refresh({ deepRefresh: true })"
6
+ hide-details
7
+ :items="ui.filteredItems.value"
8
+ :item-title="itemText"
9
+ :item-value="itemValue"
10
+ :variant="fieldVariant" />
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { type ListProps, type ListEvents, useList } from '../composables/list';
15
+ import { type FieldVariant } from '../types'
16
+
17
+ interface SelectEvents extends ListEvents {
18
+
19
+ }
20
+
21
+ interface SelectProps extends ListProps {
22
+ additionalUrl?: string
23
+ canRefresh?: boolean
24
+ canSelectNone?: boolean
25
+ fieldVariant?: FieldVariant
26
+ items?: [],
27
+ itemText?: string
28
+ itemValue?: string //inherited
29
+ multiple?: boolean
30
+ nav?: string
31
+ onFilter?: Function
32
+ textFilter?: string
33
+ }
34
+
35
+ const emit = defineEmits<SelectEvents>()
36
+
37
+ const props = withDefaults(defineProps<SelectProps>(), {
38
+ sortOrder: 'Ascending'
39
+ })
40
+
41
+ const ui = useList(props, emit, {
42
+ useBladeSrc: false,
43
+ useRouteSrc: false
44
+ })
45
+
46
+ </script>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <v-snackbar
3
+ v-model="showSnack"
4
+ :timeout="cTimeout">
5
+ {{ modelValue }}
6
+ </v-snackbar>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import { computed, ref, watch } from 'vue';
11
+
12
+
13
+ interface SnackProps {
14
+ isTimed?: boolean
15
+ modelValue?: string
16
+ timeout?: string,
17
+
18
+ }
19
+
20
+ const props = withDefaults(defineProps<SnackProps>(), {
21
+ isTimed: true,
22
+ timeout: '5000'
23
+ })
24
+
25
+ const cTimeout = computed(() => { return props.isTimed ? props.timeout : -1 })
26
+ const showSnack = ref(false)
27
+ watch(() => props.modelValue, () => {
28
+ showSnack.value = true
29
+ })
30
+
31
+ </script>
@@ -40,7 +40,7 @@
40
40
  import { computed, onMounted, ref } from 'vue'
41
41
  import VueDatePicker from '@vuepic/vue-datepicker'
42
42
  import '@vuepic/vue-datepicker/dist/main.css'
43
- import { useAuth } from '../useApi'
43
+ import { useAuth } from '../composables/auth'
44
44
  import { type SelectDateProps } from '../composables/dialogs'
45
45
 
46
46
  const props = withDefaults(defineProps<SelectDateProps>(), {
@@ -1,5 +1,5 @@
1
1
  import type { BladeMode } from '../types'
2
- import { BTStore } from '../composables/stores'
2
+ import { BTStoreDefinition } from '../composables/stores'
3
3
  import { BTApi, type PathOptions } from '../composables/api'
4
4
  import { useActionsTracker, type DoActionOptions } from '../composables/actions-tracker'
5
5
  import { ShallowRef, ComputedRef } from 'vue'
@@ -15,7 +15,7 @@ export interface GetOptions extends PathOptions, DoActionOptions {
15
15
  onGetAsync?: OnGetAsync
16
16
  /**called after get occurs successfully */
17
17
  onGetSuccessAsync?: OnGetSuccessAsync
18
- store?: BTStore
18
+ store?: BTStoreDefinition
19
19
  }
20
20
 
21
21
  export interface DeleteOptions extends PathOptions, DoActionOptions {
@@ -25,7 +25,7 @@ export interface DeleteOptions extends PathOptions, DoActionOptions {
25
25
  onDeleteAsync?: OnDoAsync
26
26
  /**Will open a dialog box requesting user confirmation for delete action */
27
27
  onDeleteSuccessAsync?: OnDoAsync
28
- store?: BTStore
28
+ store?: BTStoreDefinition
29
29
  }
30
30
 
31
31
  export interface RestoreOptions extends PathOptions, DoActionOptions {
@@ -35,7 +35,7 @@ export interface RestoreOptions extends PathOptions, DoActionOptions {
35
35
  onRestoreAsync?: OnDoSuccessAsync
36
36
  /**Called after restore succeeds */
37
37
  onRestoreSuccessAsync?: OnDoSuccessAsync
38
- store?: BTStore
38
+ store?: BTStoreDefinition
39
39
  }
40
40
 
41
41
  export interface SaveOptions extends PathOptions, DoActionOptions {
@@ -52,7 +52,7 @@ export interface SaveOptions extends PathOptions, DoActionOptions {
52
52
  onSaveAsync?: OnDoSuccessAsync
53
53
  /**Called after save succeeds */
54
54
  onSaveSuccessAsync?: OnDoSuccessAsync
55
- store?: BTStore
55
+ store?: BTStoreDefinition
56
56
  }
57
57
 
58
58
  export interface ApiActionOptions extends PathOptions, DoActionOptions {
@@ -63,7 +63,7 @@ export interface UseActionsOptions extends DoActionOptions {
63
63
  nav?: string
64
64
  proxyID?: string
65
65
  refresh?: boolean
66
- store?: BTStore
66
+ store?: BTStoreDefinition
67
67
  throwError?: boolean
68
68
  url?: string
69
69
  }
@@ -91,6 +91,12 @@ export interface BTApi {
91
91
  patch: <T>(pathOptions: PathOptions) => Promise<T | undefined>
92
92
  }
93
93
 
94
+ let current: BTApi
95
+
96
+ export function useApi(): BTApi {
97
+ return current
98
+ }
99
+
94
100
  export function createApi(options?: UseApiOptions): BTApi {
95
101
  const buildHeaders = options?.buildHeaders ?? defaultBuildHeaders
96
102
  const buildQuery = options?.buildQuery ?? defaultBuildQuery
@@ -458,7 +464,7 @@ export function createApi(options?: UseApiOptions): BTApi {
458
464
  }
459
465
  }
460
466
 
461
- return {
467
+ current = {
462
468
  buildHeaders,
463
469
  buildQuery,
464
470
  buildUrl,
@@ -468,4 +474,6 @@ export function createApi(options?: UseApiOptions): BTApi {
468
474
  patch,
469
475
  post
470
476
  }
477
+
478
+ return current
471
479
  }
@@ -31,11 +31,8 @@ export interface BaseAuthCredentials {
31
31
  userPermissions?: string[]
32
32
  }
33
33
 
34
- // const state = useStorage<BaseAuthCredentials>('auth-credentials', {})
35
- // let defaultsSet = false
36
34
  let defaultTimeZone = 'Australia/Melbourne'
37
35
 
38
- // export type FindAuthItem = (navName?: string | AuthItem) => AuthItem | undefined
39
36
  export type GetAuthUrl = (redirectPath?: string, state?: string) => string
40
37
 
41
38
  export interface CreateAuthOptions {
@@ -70,28 +67,17 @@ export interface BTAuth {
70
67
  tryLogin: () => boolean | undefined
71
68
  }
72
69
 
73
- // /**returns current timezone */
74
- // export function useTimeZone() {
75
- // return state.value.timeZone ?? defaultTimeZone
76
- // }
70
+ let current: BTAuth
77
71
 
78
- // export function useAuthData() {
79
- // return state.value
80
- // }
72
+ export function useAuth(): BTAuth {
73
+ return current
74
+ }
81
75
 
82
76
  export function createAuth(options: CreateAuthOptions): BTAuth {
83
- const router = useRouter()
84
77
  const expiryFormat = options.expiryTokenFormat ?? 'd/MM/yyyy h:mm:ss a'
85
78
  const authState = useStorage<string>('auth-credentials-state', (Math.random().toString(36).substring(4, 19) + Math.random().toString(12).substring(1, 11)))
86
79
  const state = useStorage<BaseAuthCredentials>('auth-credentials', {})
87
-
88
- // if (!defaultsSet) {
89
- // setDefaults()
90
- // defaultsSet = true
91
- // }
92
80
 
93
- // const { endDemo, isDemoing } = useDemo()
94
-
95
81
  /**can edit if navName is undefined, isGlobalAdmin, not suspended, or user permissions allow editing of this navItem */
96
82
  function canEdit(navName?: string): boolean {
97
83
  if (navName == null) return true
@@ -280,12 +266,13 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
280
266
  state.value = undefined
281
267
 
282
268
  //ensure time zone still exists
283
- setDefaults()
269
+ reinstateDefaults()
284
270
 
285
271
  //clear stores
286
272
 
287
273
  //maybe redirect
288
274
  if (navNameRedirect != null) {
275
+ const router = useRouter()
289
276
  if (router.currentRoute.value.name != navNameRedirect) {
290
277
  router.push({ name: navNameRedirect })
291
278
  }
@@ -327,13 +314,16 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
327
314
  v.isLoggedIn = true
328
315
  v.permissions = d.Permissions
329
316
  v.subscriptionCode = d.Subscription
317
+
330
318
  // v.subscriptionsInUse = d.SubscriptionsInUse
319
+ v.timeZone ??= (options.defaultTimeZone ?? defaultTimeZone)
320
+
331
321
  v.token = d
332
322
  v.userID = d.UserLoginID
333
323
  v.userPermissions = d.Permissions?.split(',') ?? []
334
324
  }
335
325
 
336
- function setDefaults() {
326
+ function reinstateDefaults() {
337
327
  state.value.timeZone ??= (options.defaultTimeZone ?? defaultTimeZone)
338
328
  }
339
329
 
@@ -363,7 +353,9 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
363
353
  return e1 <= e2
364
354
  }
365
355
 
366
- return {
356
+ reinstateDefaults()
357
+
358
+ current = {
367
359
  authState: authState.value,
368
360
  canEdit,
369
361
  canEditPermit,
@@ -379,4 +371,6 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
379
371
  setAuth,
380
372
  tryLogin
381
373
  }
374
+
375
+ return current
382
376
  }