grantthomas-nuxt 1.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.
- package/README.md +484 -0
- package/dist/module.d.mts +23 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +54 -0
- package/dist/runtime/components/AlertDisplay.d.vue.ts +2 -0
- package/dist/runtime/components/AlertDisplay.vue +55 -0
- package/dist/runtime/components/AlertDisplay.vue.d.ts +2 -0
- package/dist/runtime/components/CrudAddressSearchField.d.vue.ts +8 -0
- package/dist/runtime/components/CrudAddressSearchField.vue +117 -0
- package/dist/runtime/components/CrudAddressSearchField.vue.d.ts +8 -0
- package/dist/runtime/components/CrudApiSelectorField.d.vue.ts +30 -0
- package/dist/runtime/components/CrudApiSelectorField.vue +99 -0
- package/dist/runtime/components/CrudApiSelectorField.vue.d.ts +30 -0
- package/dist/runtime/components/CrudConfirmDialog.d.vue.ts +18 -0
- package/dist/runtime/components/CrudConfirmDialog.vue +83 -0
- package/dist/runtime/components/CrudConfirmDialog.vue.d.ts +18 -0
- package/dist/runtime/components/CrudErrorDisplay.d.vue.ts +6 -0
- package/dist/runtime/components/CrudErrorDisplay.vue +28 -0
- package/dist/runtime/components/CrudErrorDisplay.vue.d.ts +6 -0
- package/dist/runtime/components/CrudFilter.d.vue.ts +8 -0
- package/dist/runtime/components/CrudFilter.vue +348 -0
- package/dist/runtime/components/CrudFilter.vue.d.ts +8 -0
- package/dist/runtime/components/CrudFilterList.d.vue.ts +5 -0
- package/dist/runtime/components/CrudFilterList.vue +20 -0
- package/dist/runtime/components/CrudFilterList.vue.d.ts +5 -0
- package/dist/runtime/components/CrudFormDialog.d.vue.ts +31 -0
- package/dist/runtime/components/CrudFormDialog.vue +180 -0
- package/dist/runtime/components/CrudFormDialog.vue.d.ts +31 -0
- package/dist/runtime/components/CrudFormLoader.d.vue.ts +41 -0
- package/dist/runtime/components/CrudFormLoader.vue +238 -0
- package/dist/runtime/components/CrudFormLoader.vue.d.ts +41 -0
- package/dist/runtime/components/CrudListLoader.d.vue.ts +37 -0
- package/dist/runtime/components/CrudListLoader.vue +130 -0
- package/dist/runtime/components/CrudListLoader.vue.d.ts +37 -0
- package/dist/runtime/components/CrudPaginatedLoader.d.vue.ts +70 -0
- package/dist/runtime/components/CrudPaginatedLoader.vue +415 -0
- package/dist/runtime/components/CrudPaginatedLoader.vue.d.ts +70 -0
- package/dist/runtime/components/CrudUploadField.d.vue.ts +23 -0
- package/dist/runtime/components/CrudUploadField.vue +311 -0
- package/dist/runtime/components/CrudUploadField.vue.d.ts +23 -0
- package/dist/runtime/components/CrudUploadFieldSelection.d.vue.ts +18 -0
- package/dist/runtime/components/CrudUploadFieldSelection.vue +178 -0
- package/dist/runtime/components/CrudUploadFieldSelection.vue.d.ts +18 -0
- package/dist/runtime/composables/PublicClientApplicationSingleton.d.ts +5 -0
- package/dist/runtime/composables/PublicClientApplicationSingleton.js +14 -0
- package/dist/runtime/composables/useAlertService.d.ts +14 -0
- package/dist/runtime/composables/useAlertService.js +38 -0
- package/dist/runtime/composables/useCrudApi.d.ts +35 -0
- package/dist/runtime/composables/useCrudApi.js +314 -0
- package/dist/runtime/composables/useCrudConverters.d.ts +33 -0
- package/dist/runtime/composables/useCrudConverters.js +202 -0
- package/dist/runtime/composables/useListenerService.d.ts +7 -0
- package/dist/runtime/composables/useListenerService.js +43 -0
- package/dist/runtime/composables/useMSAuth.d.ts +13 -0
- package/dist/runtime/composables/useMSAuth.js +125 -0
- package/dist/runtime/composables/usePreviousRoute.d.ts +1 -0
- package/dist/runtime/composables/usePreviousRoute.js +4 -0
- package/dist/runtime/constants/crudAuthInterceptor.d.ts +6 -0
- package/dist/runtime/constants/crudAuthInterceptor.js +8 -0
- package/dist/runtime/plugin.client.d.ts +2 -0
- package/dist/runtime/plugin.client.js +11 -0
- package/dist/runtime/plugin.luxon.d.ts +2 -0
- package/dist/runtime/plugin.luxon.js +5 -0
- package/dist/runtime/plugins/track-previous-route.client.d.ts +2 -0
- package/dist/runtime/plugins/track-previous-route.client.js +10 -0
- package/dist/runtime/server/api/maps/autocomplete.d.ts +5 -0
- package/dist/runtime/server/api/maps/autocomplete.js +12 -0
- package/dist/runtime/server/api/maps/geocode.d.ts +5 -0
- package/dist/runtime/server/api/maps/geocode.js +12 -0
- package/dist/runtime/server/api/maps/places.d.ts +5 -0
- package/dist/runtime/server/api/maps/places.js +12 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/types.d.mts +9 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Get your module up and running quickly.
|
|
3
|
+
|
|
4
|
+
Find and replace all on all files (CMD+SHIFT+F):
|
|
5
|
+
- Name: Crud Nuxt
|
|
6
|
+
- Package name: crud-nuxt
|
|
7
|
+
- Description: My new Nuxt module
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
# Crud Nuxt
|
|
11
|
+
|
|
12
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
13
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
14
|
+
[![License][license-src]][license-href]
|
|
15
|
+
[![Nuxt][nuxt-src]][nuxt-href]
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
<!-- Highlight some of the features your module provide here -->
|
|
20
|
+
- Crud operations
|
|
21
|
+
- Components for pagination and filtering
|
|
22
|
+
- Baz
|
|
23
|
+
|
|
24
|
+
## Quick Setup
|
|
25
|
+
|
|
26
|
+
Install the module to your Nuxt application with one command:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx nuxi module add crud-nuxt
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
That's it! You can now use My Module in your Nuxt app ✨
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<details>
|
|
38
|
+
<summary>Local development</summary>
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Install dependencies
|
|
42
|
+
npm install
|
|
43
|
+
|
|
44
|
+
# Generate type stubs
|
|
45
|
+
npm run dev:prepare
|
|
46
|
+
|
|
47
|
+
# Develop with the playground
|
|
48
|
+
npm run dev
|
|
49
|
+
|
|
50
|
+
# Build the playground
|
|
51
|
+
npm run dev:build
|
|
52
|
+
|
|
53
|
+
# Run ESLint
|
|
54
|
+
npm run lint
|
|
55
|
+
|
|
56
|
+
# Run Vitest
|
|
57
|
+
npm run test
|
|
58
|
+
npm run test:watch
|
|
59
|
+
|
|
60
|
+
# Release new version
|
|
61
|
+
npm run release
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
</details>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# CRUD API and Pagination Loader
|
|
68
|
+
|
|
69
|
+
This repository provides a composable for managing CRUD operations and a Vue component for rendering a paginated list of items with filtering and actions.
|
|
70
|
+
|
|
71
|
+
## Table of Contents
|
|
72
|
+
|
|
73
|
+
- [useCrudApi Composable](#usecrudapi-composable)
|
|
74
|
+
- [CrudPaginatedLoader Component](#crudpaginatedloader-component)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## useCrudApi Composable
|
|
79
|
+
|
|
80
|
+
The `useCrudApi` composable provides a set of functions and reactive state management for performing CRUD operations against a specified API endpoint. It integrates authentication handling, pagination, filtering, and error management.
|
|
81
|
+
|
|
82
|
+
### Usage
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
import { useCrudApi } from 'path/to/useCrudApi';
|
|
86
|
+
|
|
87
|
+
const { getItems, createItem, updateItem, deleteItem, items, currentPage } = useCrudApi('your/api/path');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Parameters
|
|
91
|
+
|
|
92
|
+
- **path**: `string` - The API endpoint path.
|
|
93
|
+
- **watchPage**: `boolean` (optional, default: `true`) - Whether to watch the current page for changes.
|
|
94
|
+
- **transformItem**: `Function` (optional) - A function to transform a single item.
|
|
95
|
+
- **transformItems**: `Function` (optional) - A function to transform multiple items.
|
|
96
|
+
|
|
97
|
+
### Returns
|
|
98
|
+
|
|
99
|
+
- **items**: `Ref<Array>` - The list of items fetched from the API.
|
|
100
|
+
- **currentPage**: `Ref<number>` - The current page number.
|
|
101
|
+
- **totalPages**: `Ref<number>` - The total number of pages available.
|
|
102
|
+
- **totalItems**: `Ref<number>` - The total number of items available.
|
|
103
|
+
- **perPage**: `Ref<number>` - The number of items per page.
|
|
104
|
+
- **filters**: `Ref<Record<string, any>>[]` - The active filters.
|
|
105
|
+
- **item**: `Ref<any>` - The currently selected item.
|
|
106
|
+
- **count**: `Ref<number>` - The count of items.
|
|
107
|
+
- **listErrors**: `Ref<Record<string, any>>` - Errors encountered during list fetches.
|
|
108
|
+
- **formErrors**: `Ref<Record<string, any>>` - Errors encountered during form submissions.
|
|
109
|
+
- **itemErrors**: `Ref<Record<string, any>>` - Errors encountered when fetching or updating a single item.
|
|
110
|
+
- **countErrors**: `Ref<Record<string, any>>` - Errors encountered when fetching counts.
|
|
111
|
+
- **exportErrors**: `Ref<Record<string, any>>` - Errors encountered during export operations.
|
|
112
|
+
- **hasFormErrors**: `Ref<boolean>` - Indicates if there are form errors.
|
|
113
|
+
- **hasItemErrors**: `Ref<boolean>` - Indicates if there are item errors.
|
|
114
|
+
- **hasCountErrors**: `Ref<boolean>` - Indicates if there are count errors.
|
|
115
|
+
- **hasExportErrors**: `Ref<boolean>` - Indicates if there are export errors.
|
|
116
|
+
- **listPending**: `Ref<boolean>` - Indicates if a list fetch is pending.
|
|
117
|
+
- **formPending**: `Ref<boolean>` - Indicates if a form operation is pending.
|
|
118
|
+
- **itemPending**: `Ref<boolean>` - Indicates if fetching or updating an item is pending.
|
|
119
|
+
- **countPending**: `Ref<boolean>` - Indicates if a count fetch is pending.
|
|
120
|
+
- **exportPending**: `Ref<boolean>` - Indicates if an export operation is pending.
|
|
121
|
+
- **getItems**: `Function` - Fetches the items from the API.
|
|
122
|
+
- **createItem**: `Function` - Creates a new item in the API.
|
|
123
|
+
- **updateItem**: `Function` - Updates an existing item in the API.
|
|
124
|
+
- **deleteItem**: `Function` - Deletes an item from the API.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## CrudPaginatedLoader Component
|
|
129
|
+
|
|
130
|
+
The `CrudPaginatedLoader` component provides a UI for displaying a paginated list of items, along with options for filtering, creating, updating, and deleting items.
|
|
131
|
+
|
|
132
|
+
### Usage
|
|
133
|
+
|
|
134
|
+
```vue
|
|
135
|
+
|
|
136
|
+
<script setup>
|
|
137
|
+
|
|
138
|
+
</script>
|
|
139
|
+
<template>
|
|
140
|
+
<crud-paginated-loader
|
|
141
|
+
path="your/api/path"
|
|
142
|
+
:custom-filters="{}"
|
|
143
|
+
create-title="Create Item"
|
|
144
|
+
update-title="Update Item"
|
|
145
|
+
delete-title="Delete Item"
|
|
146
|
+
:per-page="10"
|
|
147
|
+
:listeners="['onItemCreated']" <!-- List of events to listen for from useListenerService and reload results when the happen -->
|
|
148
|
+
:await="false" <!-- Set to true to wait for the fetchItems function to resolve before rendering -->
|
|
149
|
+
>
|
|
150
|
+
<!-- Your custom slots here -->
|
|
151
|
+
<template #before="{
|
|
152
|
+
items,
|
|
153
|
+
listPending,
|
|
154
|
+
createForm,
|
|
155
|
+
updateForm,
|
|
156
|
+
deleteForm,
|
|
157
|
+
formPending,
|
|
158
|
+
exportAction,
|
|
159
|
+
exportPending,
|
|
160
|
+
exportErrors
|
|
161
|
+
}">
|
|
162
|
+
<!-- Your custom content here -->
|
|
163
|
+
<v-btn @click="createForm">Open create form</v-btn>
|
|
164
|
+
<v-btn :loading="exportPending" @click="exportItems">Export filtered items</v-btn>
|
|
165
|
+
</template>
|
|
166
|
+
|
|
167
|
+
<template #default="{
|
|
168
|
+
items, // The list of items in current page
|
|
169
|
+
pending, // If the list is loading
|
|
170
|
+
updateForm, // Action to show the update form
|
|
171
|
+
deleteForm, // Action to show the delete form
|
|
172
|
+
formPending // If the form is loading
|
|
173
|
+
}">
|
|
174
|
+
<!-- Your item list here -->
|
|
175
|
+
<v-simple-table>
|
|
176
|
+
<template #default="{ items }">
|
|
177
|
+
<tr v-for="item in items" :key="item.id">
|
|
178
|
+
<td>{{ item.name }}</td>
|
|
179
|
+
<td>{{ item.email }}</td>
|
|
180
|
+
<td>
|
|
181
|
+
<v-btn @click="updateForm(item.id)">Edit</v-btn>
|
|
182
|
+
<v-btn @click="deleteForm(item.id)">Delete</v-btn>
|
|
183
|
+
</td>
|
|
184
|
+
</tr>
|
|
185
|
+
</template>
|
|
186
|
+
</v-simple-table>
|
|
187
|
+
</template>
|
|
188
|
+
|
|
189
|
+
<template #form="{
|
|
190
|
+
action, // The action to perform (create, update, delete)
|
|
191
|
+
item, // The item object to update prior to form submission
|
|
192
|
+
errors // The errors with any form submission
|
|
193
|
+
}">
|
|
194
|
+
<!-- Your form layout here typically in it's own component for neatness and reusability -->
|
|
195
|
+
<v-text-field
|
|
196
|
+
v-model="item.name"
|
|
197
|
+
label="Name"
|
|
198
|
+
:error="errors.name"
|
|
199
|
+
:error-messages="errors.name"
|
|
200
|
+
/>
|
|
201
|
+
<v-text-field
|
|
202
|
+
v-model="item.email"
|
|
203
|
+
label="Email"
|
|
204
|
+
:error="errors.email"
|
|
205
|
+
:error-messages="errors.email"
|
|
206
|
+
/>
|
|
207
|
+
</template>
|
|
208
|
+
|
|
209
|
+
</crud-paginated-loader>
|
|
210
|
+
</template>
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Props
|
|
215
|
+
|
|
216
|
+
- **fetchItems**: `Function` - A function to fetch the items.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# useListenerService
|
|
224
|
+
|
|
225
|
+
The `useListenerService` is a utility service for managing event listeners in a JavaScript application. It allows you to add, remove, and notify listeners based on specific events.
|
|
226
|
+
|
|
227
|
+
## Overview
|
|
228
|
+
|
|
229
|
+
This service is useful for applications that need to respond to various events without tightly coupling components. It provides a way to manage listeners dynamically, ensuring that they can be added or removed as needed.
|
|
230
|
+
|
|
231
|
+
## Types
|
|
232
|
+
|
|
233
|
+
### Listener
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
type Listener = {
|
|
237
|
+
id: string; // Unique identifier for the listener
|
|
238
|
+
event: string; // Name of the event to listen for
|
|
239
|
+
callback: Function; // Function to call when the event occurs
|
|
240
|
+
};
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Functions
|
|
244
|
+
|
|
245
|
+
### `useListenerService`
|
|
246
|
+
|
|
247
|
+
This function initializes and returns the listener service, providing methods to manage listeners.
|
|
248
|
+
|
|
249
|
+
#### Returns
|
|
250
|
+
|
|
251
|
+
An object containing the following methods:
|
|
252
|
+
|
|
253
|
+
- **removeLocalListeners**:
|
|
254
|
+
- Removes all listeners that were added during the current session.
|
|
255
|
+
|
|
256
|
+
- **removeLocalListenersWithEvent(event: string)**:
|
|
257
|
+
- Removes all local listeners associated with a specific event.
|
|
258
|
+
- **Parameters**:
|
|
259
|
+
- `event`: The name of the event whose listeners should be removed.
|
|
260
|
+
|
|
261
|
+
- **addListener(event: string, callback: Function)**:
|
|
262
|
+
- Adds a new listener for the specified event.
|
|
263
|
+
- **Parameters**:
|
|
264
|
+
- `event`: The name of the event to listen for.
|
|
265
|
+
- `callback`: The function to call when the event is triggered.
|
|
266
|
+
- **Returns**: The unique identifier (ID) of the added listener.
|
|
267
|
+
|
|
268
|
+
- **removeListener(id: string)**:
|
|
269
|
+
- Removes a listener by its unique identifier.
|
|
270
|
+
- **Parameters**:
|
|
271
|
+
- `id`: The unique identifier of the listener to be removed.
|
|
272
|
+
|
|
273
|
+
- **notify(key: string, data: any)**:
|
|
274
|
+
- Triggers all callbacks for listeners associated with the specified event.
|
|
275
|
+
- **Parameters**:
|
|
276
|
+
- `key`: The name of the event to notify.
|
|
277
|
+
- `data`: The data to pass to the callback functions.
|
|
278
|
+
|
|
279
|
+
## Example Usage
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
const listenerService = useListenerService();
|
|
283
|
+
|
|
284
|
+
// Adding a listener
|
|
285
|
+
const listenerId = listenerService.addListener('myEvent', (data) => {
|
|
286
|
+
console.log('Event received:', data);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Notifying listeners
|
|
290
|
+
listenerService.notify('myEvent', { key: 'value' });
|
|
291
|
+
|
|
292
|
+
// Removing a specific listener
|
|
293
|
+
listenerService.removeListener(listenerId);
|
|
294
|
+
|
|
295
|
+
// Removing all local listeners
|
|
296
|
+
listenerService.removeLocalListeners();
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
# `useCrudConverters`
|
|
300
|
+
|
|
301
|
+
This composable provides a variety of utility functions for handling CRUD operations, formatting dates, converting files, and manipulating query strings in a Nuxt application.
|
|
302
|
+
|
|
303
|
+
## Usage
|
|
304
|
+
|
|
305
|
+
Import `useCrudConverters` where needed in your Nuxt components or composables.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
import { useCrudConverters } from '~/path/to/composables';
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Available Methods
|
|
312
|
+
|
|
313
|
+
#### **`localDateForDb(date: Date): string`**
|
|
314
|
+
Converts a local `Date` object to a UTC ISO string formatted for database storage.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
#### **`cloneDeep(obj: any): any`**
|
|
319
|
+
Performs a deep clone of the provided object.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
#### **`flattenQuery(obj: Record<string, any>, prefix = ''): Record<string, any>`**
|
|
324
|
+
Flattens nested objects into a single-level query string-compatible format.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
#### **`parseQuery(query: string): Record<string, any>`**
|
|
329
|
+
Parses a query string into a JavaScript object.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
#### **`stringifyQuery(params: Record<string, any>, prefix: string = '', options: StringifyOptions): string`**
|
|
334
|
+
Converts an object to a query string with configurable formatting options.
|
|
335
|
+
|
|
336
|
+
- `params`: The object to stringify.
|
|
337
|
+
- `prefix`: Prefix for the query string.
|
|
338
|
+
- `options`: Optional settings such as `arrayFormat` and `skipNull`.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
#### **`getFileType(file): number | null`**
|
|
343
|
+
Determines the file type based on its MIME type.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
#### **`mimeTypeToMdiIcon(mimeType: string): string`**
|
|
348
|
+
Maps MIME types to Material Design Icons.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
#### **`toBase64(file): Promise<string>`**
|
|
353
|
+
Converts a file to a Base64-encoded string.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
#### **`convertAddress(item: Record<string, any>, separator = ', '): string`**
|
|
358
|
+
Concatenates address components into a formatted string.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
#### **`formatRange(min: string, max: string, separator = ' - '): string`**
|
|
363
|
+
Formats a date range string for display, adjusting based on current date context.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
#### **`formatDate(date: Date, format: Intl.DateTimeFormatOptions): string`**
|
|
368
|
+
Formats a `Date` object according to provided formatting options.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
#### **`formatStringDate(dateString: string, format: Intl.DateTimeFormatOptions): string`**
|
|
373
|
+
Formats a date string according to specified options.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
#### **`parseDate(dateStr: string): Date`**
|
|
378
|
+
Parses a date string into a `Date` object.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
#### **`filtersToBase64String(filters: any): string`**
|
|
383
|
+
Encodes filter values into a Base64-encoded JSON string.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
#### **`base64StringToObj(base64String: string): any | null`**
|
|
388
|
+
Decodes a Base64 string back into a JavaScript object.
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
#### **`extractFilterValues(filters: { key: string; value: any }[]): Record<string, any>`**
|
|
393
|
+
Extracts key-value pairs from an array of filter objects.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
#### **`uploadFilenameToUrl(fileLocation: string, size: string): string`**
|
|
398
|
+
Constructs a URL for an uploaded file with specified size prefix (`thumbnail`, `medium`, `large`).
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
#### **`uploadToUrl(upload: { fileLocation: string }, size: string): string`**
|
|
403
|
+
Similar to `uploadFilenameToUrl` but takes an object with a `fileLocation` property.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
#### **`outputDateFromDb(dateStr: string, formatOut = 'dd/MM/yyyy'): string`**
|
|
408
|
+
Formats a UTC ISO date string from the database to the local timezone format.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
#### **`inputDateForDb(dateStr: string, formatIn = 'dd/MM/yyyy'): string`**
|
|
413
|
+
Parses a date string in the local timezone and converts it to a UTC ISO date string for storage.
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
### Example Usages
|
|
418
|
+
|
|
419
|
+
1. **Flattening Query Parameters**
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
const params = {
|
|
423
|
+
user: { id: 1, name: "Alice" },
|
|
424
|
+
filters: { age: { min: 18, max: 30 }, isActive: true }
|
|
425
|
+
};
|
|
426
|
+
const flatParams = flattenQuery(params);
|
|
427
|
+
console.log(flatParams);
|
|
428
|
+
// Output: { "user[id]": 1, "user[name]": "Alice", "filters[age][min]": 18, "filters[age][max]": 30, "filters[isActive]": true }
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
2. **Encoding and Decoding Filters**
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
const filters = { status: "active", roles: ["admin", "user"] };
|
|
435
|
+
const encodedFilters = filtersToBase64String(filters);
|
|
436
|
+
const decodedFilters = base64StringToObj(encodedFilters);
|
|
437
|
+
console.log(decodedFilters);
|
|
438
|
+
// Output: { status: "active", roles: ["admin", "user"] }
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
3. **Stringifying Query with Custom Options**
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
const query = { name: "John", roles: ["admin", "user"], isActive: true };
|
|
445
|
+
const queryString = stringifyQuery(query, '', { arrayFormat: 'bracket' });
|
|
446
|
+
console.log(queryString);
|
|
447
|
+
// Output: "name=John&roles[]=admin&roles[]=user&isActive=true"
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
4. **Formatting Dates for Display and Storage**
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
const dbDate = outputDateFromDb("2024-10-26T12:00:00Z", "dd MMM yyyy");
|
|
454
|
+
console.log(dbDate);
|
|
455
|
+
// Output (localized): "26 Oct 2024"
|
|
456
|
+
|
|
457
|
+
const isoDate = inputDateForDb("26/10/2024", "dd/MM/yyyy");
|
|
458
|
+
console.log(isoDate);
|
|
459
|
+
// Output: "2024-10-26T00:00:00.000Z" (UTC format)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
5. **Converting a File to Base64**
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
const fileInput = document.querySelector("input[type='file']");
|
|
466
|
+
fileInput.addEventListener('change', async (event) => {
|
|
467
|
+
const file = event.target.files[0];
|
|
468
|
+
const base64String = await toBase64(file);
|
|
469
|
+
console.log(base64String);
|
|
470
|
+
});
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
<!-- Badges -->
|
|
474
|
+
[npm-version-src]: https://img.shields.io/npm/v/crud-nuxt/latest.svg?style=flat&colorA=020420&colorB=00DC82
|
|
475
|
+
[npm-version-href]: https://npmjs.com/package/crud-nuxt
|
|
476
|
+
|
|
477
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/crud-nuxt.svg?style=flat&colorA=020420&colorB=00DC82
|
|
478
|
+
[npm-downloads-href]: https://npmjs.com/package/crud-nuxt
|
|
479
|
+
|
|
480
|
+
[license-src]: https://img.shields.io/npm/l/crud-nuxt.svg?style=flat&colorA=020420&colorB=00DC82
|
|
481
|
+
[license-href]: https://npmjs.com/package/crud-nuxt
|
|
482
|
+
|
|
483
|
+
[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
|
|
484
|
+
[nuxt-href]: https://nuxt.com
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
|
|
3
|
+
interface azureAdB2COptions {
|
|
4
|
+
clientId: string;
|
|
5
|
+
authority: string;
|
|
6
|
+
knownAuthorities?: Array<string>;
|
|
7
|
+
redirectUri: string;
|
|
8
|
+
postLogoutRedirectUri?: string;
|
|
9
|
+
navigateToLoginRequestUrl: boolean;
|
|
10
|
+
scopes?: string[];
|
|
11
|
+
}
|
|
12
|
+
interface CrudModuleOptions {
|
|
13
|
+
apiBaseUrl?: string;
|
|
14
|
+
storageBaseUrl?: string;
|
|
15
|
+
additionalHeaders?: Record<string, string>;
|
|
16
|
+
azureAdB2C?: azureAdB2COptions;
|
|
17
|
+
googleMapsApiKey?: string;
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
}
|
|
20
|
+
declare const _default: _nuxt_schema.NuxtModule<CrudModuleOptions, CrudModuleOptions, false>;
|
|
21
|
+
|
|
22
|
+
export { _default as default };
|
|
23
|
+
export type { CrudModuleOptions, azureAdB2COptions };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addServerHandler, addPlugin, addComponentsDir, addImportsDir, installModule } from '@nuxt/kit';
|
|
2
|
+
|
|
3
|
+
const module = defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "@grantthomas/nuxt",
|
|
6
|
+
configKey: "grantThomasNuxt"
|
|
7
|
+
},
|
|
8
|
+
defaults: {
|
|
9
|
+
debug: true,
|
|
10
|
+
additionalHeaders: {
|
|
11
|
+
"Content-Type": "application/json",
|
|
12
|
+
"Accept": "application/json"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
async setup(options, nuxt) {
|
|
16
|
+
const resolver = createResolver(import.meta.url);
|
|
17
|
+
nuxt.options.runtimeConfig.public.crudNuxt = options;
|
|
18
|
+
nuxt.options.build.transpile.push("qs");
|
|
19
|
+
addServerHandler({
|
|
20
|
+
route: "/api/maps/autocomplete",
|
|
21
|
+
handler: resolver.resolve("runtime/server/api/maps/autocomplete")
|
|
22
|
+
});
|
|
23
|
+
addServerHandler({
|
|
24
|
+
route: "/api/maps/places",
|
|
25
|
+
handler: resolver.resolve("runtime/server/api/maps/places")
|
|
26
|
+
});
|
|
27
|
+
addServerHandler({
|
|
28
|
+
route: "/api/maps/geocode",
|
|
29
|
+
handler: resolver.resolve("runtime/server/api/maps/geocode")
|
|
30
|
+
});
|
|
31
|
+
addPlugin({
|
|
32
|
+
src: resolver.resolve("runtime/plugins/track-previous-route.client"),
|
|
33
|
+
mode: "client"
|
|
34
|
+
});
|
|
35
|
+
await addComponentsDir({
|
|
36
|
+
path: resolver.resolve("runtime/components")
|
|
37
|
+
});
|
|
38
|
+
addImportsDir(resolver.resolve("runtime/composables"));
|
|
39
|
+
addImportsDir(resolver.resolve("runtime/constants"));
|
|
40
|
+
addImportsDir(resolver.resolve("runtime/utils"));
|
|
41
|
+
await installModule("@nuxt/image");
|
|
42
|
+
await installModule("vuetify-nuxt-module");
|
|
43
|
+
await installModule("@vueuse/nuxt");
|
|
44
|
+
await installModule("@nuxt/scripts");
|
|
45
|
+
addPlugin({
|
|
46
|
+
src: resolver.resolve("runtime/plugin.luxon"),
|
|
47
|
+
mode: "all"
|
|
48
|
+
// Available both client and server-side
|
|
49
|
+
});
|
|
50
|
+
addPlugin(resolver.resolve("./runtime/plugin.client"));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export { module as default };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useAlertService } from "../composables/useAlertService";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
const { alertMessage, alertActive } = useAlertService();
|
|
5
|
+
const message = computed(() => {
|
|
6
|
+
if (!alertMessage.value || !alertActive.value) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return typeof alertMessage.value === "string" ? alertMessage.value : alertMessage.value.message;
|
|
10
|
+
});
|
|
11
|
+
const color = computed(() => {
|
|
12
|
+
if (!alertMessage.value || !alertActive.value) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return typeof alertMessage.value === "string" ? "success" : alertMessage.value.color || "success";
|
|
16
|
+
});
|
|
17
|
+
const location = computed(() => {
|
|
18
|
+
if (!alertMessage.value || !alertActive.value) {
|
|
19
|
+
return "";
|
|
20
|
+
}
|
|
21
|
+
return typeof alertMessage.value === "string" ? "" : alertMessage.value.location || "";
|
|
22
|
+
});
|
|
23
|
+
const icon = computed(() => {
|
|
24
|
+
if (!alertMessage.value || !alertActive.value) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return typeof alertMessage.value === "string" ? null : alertMessage.value.icon || null;
|
|
28
|
+
});
|
|
29
|
+
const clickable = computed(() => {
|
|
30
|
+
if (!alertMessage.value || !alertActive.value || typeof alertMessage.value === "string" || !alertMessage.value.onClick) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
35
|
+
const onClick = () => {
|
|
36
|
+
if (!clickable.value) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
alertMessage.value.onClick();
|
|
40
|
+
};
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<v-snackbar v-model="alertActive" :color="color" timeout="3000" :top="true" :location="location">
|
|
45
|
+
<div class="d-flex align-center justify-between">
|
|
46
|
+
<v-icon v-if="icon" :icon="icon" class="mr-2"></v-icon>
|
|
47
|
+
<div class="flex-fill">
|
|
48
|
+
{{ message }}
|
|
49
|
+
</div>
|
|
50
|
+
<v-btn size="small" class="ml-2" v-if="clickable" @click="onClick" :icon="true">
|
|
51
|
+
<v-icon icon="mdi-chevron-right"/>
|
|
52
|
+
</v-btn>
|
|
53
|
+
</div>
|
|
54
|
+
</v-snackbar>
|
|
55
|
+
</template>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
+
hint: string;
|
|
3
|
+
label: string;
|
|
4
|
+
placeholder: string;
|
|
5
|
+
countries: unknown[];
|
|
6
|
+
$props: any;
|
|
7
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
8
|
+
export default _default;
|