@awes-io/ui 2.142.0 → 2.143.0
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/CHANGELOG.md +58 -0
- package/assets/css/components/_index.css +7 -1
- package/assets/css/components/animation.css +38 -32
- package/assets/css/components/content-placeholder.css +103 -0
- package/assets/css/components/empty-container.css +69 -1
- package/assets/css/components/filter-chosen.css +6 -0
- package/assets/css/components/filter-date-range.css +17 -1
- package/assets/css/components/filter-month.css +23 -17
- package/assets/css/components/filter-select.css +11 -0
- package/assets/css/components/layout.css +1 -32
- package/assets/css/components/modal.css +1 -1
- package/assets/css/components/number.css +12 -0
- package/assets/css/components/page-aside.css +54 -0
- package/assets/js/css.js +1 -1
- package/assets/js/icons/mono.js +59 -91
- package/assets/js/icons/multicolor.js +1 -31
- package/components/1_atoms/AwContentPlaceholder.vue +60 -0
- package/components/1_atoms/AwFlow.vue +21 -48
- package/components/1_atoms/AwLabel.vue +1 -1
- package/components/2_molecules/AwButton.vue +1 -1
- package/components/2_molecules/AwEmptyContainer.vue +74 -72
- package/components/2_molecules/AwNumber.vue +180 -0
- package/components/2_molecules/AwSelect.vue +11 -4
- package/components/3_organisms/AwFilterChosen.vue +73 -0
- package/components/3_organisms/AwFilterDateRange.vue +177 -0
- package/components/3_organisms/AwFilterMonth.vue +37 -40
- package/components/3_organisms/AwFilterSelect.vue +368 -0
- package/components/3_organisms/AwImageUpload.vue +1 -1
- package/components/3_organisms/AwMarkdownEditor.vue +0 -0
- package/components/3_organisms/AwMultiBlockBuilder.vue +1 -1
- package/components/3_organisms/AwTable/AwTableBuilder.vue +12 -60
- package/components/4_pages/AwPageAside.vue +108 -0
- package/components/5_layouts/AwLayoutCenter.vue +3 -8
- package/components/5_layouts/_AwUserMenu.vue +1 -1
- package/dist/css/aw-icons.css +26 -0
- package/dist/fonts/aw-icons.svg +18 -0
- package/dist/fonts/aw-icons.ttf +0 -0
- package/dist/fonts/aw-icons.woff +0 -0
- package/dist/fonts/aw-icons.woff2 +0 -0
- package/docs/_template.md +80 -0
- package/docs/components/atoms/aw-accordion-fold.md +91 -0
- package/docs/components/atoms/aw-action-card-body.md +67 -0
- package/docs/components/atoms/aw-action-card.md +94 -0
- package/docs/components/atoms/aw-action-icon.md +88 -0
- package/docs/components/atoms/aw-avatar.md +106 -0
- package/docs/components/atoms/aw-card.md +112 -0
- package/docs/components/atoms/aw-checkbox.md +112 -0
- package/docs/components/atoms/aw-content-placeholder.md +116 -0
- package/docs/components/atoms/aw-description.md +83 -0
- package/docs/components/atoms/aw-dock.md +84 -0
- package/docs/components/atoms/aw-dropdown-button.md +94 -0
- package/docs/components/atoms/aw-dropdown.md +128 -0
- package/docs/components/atoms/aw-file.md +73 -0
- package/docs/components/atoms/aw-flow.md +92 -0
- package/docs/components/atoms/aw-grid.md +91 -0
- package/docs/components/atoms/aw-headline.md +71 -0
- package/docs/components/atoms/aw-icon-system-color.md +121 -0
- package/docs/components/atoms/aw-icon-system-mono.md +205 -0
- package/docs/components/atoms/aw-icon.md +235 -0
- package/docs/components/atoms/aw-info.md +85 -0
- package/docs/components/atoms/aw-input.md +120 -0
- package/docs/components/atoms/aw-label.md +83 -0
- package/docs/components/atoms/aw-link.md +99 -0
- package/docs/components/atoms/aw-list.md +88 -0
- package/docs/components/atoms/aw-progress.md +70 -0
- package/docs/components/atoms/aw-radio.md +109 -0
- package/docs/components/atoms/aw-refresh-wrapper.md +81 -0
- package/docs/components/atoms/aw-select-native.md +106 -0
- package/docs/components/atoms/aw-slider.md +82 -0
- package/docs/components/atoms/aw-sub-headline.md +73 -0
- package/docs/components/atoms/aw-switcher.md +115 -0
- package/docs/components/atoms/aw-tag.md +80 -0
- package/docs/components/atoms/aw-title.md +70 -0
- package/docs/components/atoms/aw-toggler.md +69 -0
- package/docs/components/layouts/aw-layout-center.md +168 -0
- package/docs/components/layouts/aw-layout-error.md +153 -0
- package/docs/components/layouts/aw-layout-provider.md +238 -0
- package/docs/components/layouts/aw-layout.md +88 -0
- package/docs/components/molecules/aw-action-button.md +91 -0
- package/docs/components/molecules/aw-alert.md +96 -0
- package/docs/components/molecules/aw-badge.md +108 -0
- package/docs/components/molecules/aw-banner-text.md +90 -0
- package/docs/components/molecules/aw-button-nav.md +46 -0
- package/docs/components/molecules/aw-button.md +123 -0
- package/docs/components/molecules/aw-description-input.md +67 -0
- package/docs/components/molecules/aw-empty-container.md +86 -0
- package/docs/components/molecules/aw-island.md +234 -0
- package/docs/components/molecules/aw-number.md +138 -0
- package/docs/components/molecules/aw-select-object.md +401 -0
- package/docs/components/molecules/aw-select.md +215 -0
- package/docs/components/molecules/aw-tab-nav.md +108 -0
- package/docs/components/molecules/aw-tel.md +129 -0
- package/docs/components/molecules/aw-textarea.md +83 -0
- package/docs/components/molecules/aw-userpic.md +115 -0
- package/docs/components/organisms/aw-address-block.md +64 -0
- package/docs/components/organisms/aw-address.md +132 -0
- package/docs/components/organisms/aw-birthday-picker.md +73 -0
- package/docs/components/organisms/aw-bottom-bar.md +66 -0
- package/docs/components/organisms/aw-calendar-days.md +115 -0
- package/docs/components/organisms/aw-calendar-nav.md +98 -0
- package/docs/components/organisms/aw-calendar-view.md +98 -0
- package/docs/components/organisms/aw-calendar.md +166 -0
- package/docs/components/organisms/aw-chart.md +154 -0
- package/docs/components/organisms/aw-chip-select.md +164 -0
- package/docs/components/organisms/aw-chip.md +126 -0
- package/docs/components/organisms/aw-code-snippet.md +94 -0
- package/docs/components/organisms/aw-code.md +132 -0
- package/docs/components/organisms/aw-context-menu.md +117 -0
- package/docs/components/organisms/aw-cropper.md +151 -0
- package/docs/components/organisms/aw-date.md +161 -0
- package/docs/components/organisms/aw-display-date.md +33 -0
- package/docs/components/organisms/aw-download-link.md +46 -0
- package/docs/components/organisms/aw-fetch-data.md +161 -0
- package/docs/components/organisms/aw-filter-chosen.md +226 -0
- package/docs/components/organisms/aw-filter-date-range.md +205 -0
- package/docs/components/organisms/aw-filter-month.md +43 -0
- package/docs/components/organisms/aw-filter-select.md +225 -0
- package/docs/components/organisms/aw-form.md +174 -0
- package/docs/components/organisms/aw-gmap-marker.md +86 -0
- package/docs/components/organisms/aw-gmap.md +90 -0
- package/docs/components/organisms/aw-image-upload.md +56 -0
- package/docs/components/organisms/aw-island-avatar.md +87 -0
- package/docs/components/organisms/aw-markdown-editor.md +104 -0
- package/docs/components/organisms/aw-modal-buttons.md +57 -0
- package/docs/components/organisms/aw-modal.md +246 -0
- package/docs/components/organisms/aw-model-edit.md +74 -0
- package/docs/components/organisms/aw-money.md +53 -0
- package/docs/components/organisms/aw-multi-block-builder.md +165 -0
- package/docs/components/organisms/aw-pagination.md +121 -0
- package/docs/components/organisms/aw-password.md +103 -0
- package/docs/components/organisms/aw-preview-card.md +45 -0
- package/docs/components/organisms/aw-search.md +116 -0
- package/docs/components/organisms/aw-subnav.md +122 -0
- package/docs/components/organisms/aw-table-builder.md +165 -0
- package/docs/components/organisms/aw-table-col.md +123 -0
- package/docs/components/organisms/aw-table-head.md +92 -0
- package/docs/components/organisms/aw-table-row.md +91 -0
- package/docs/components/organisms/aw-table.md +172 -0
- package/docs/components/organisms/aw-tags.md +54 -0
- package/docs/components/organisms/aw-toggle-show-aside.md +43 -0
- package/docs/components/organisms/aw-uploader-files.md +125 -0
- package/docs/components/organisms/aw-uploader.md +163 -0
- package/docs/components/organisms/aw-user-menu.md +87 -0
- package/docs/components/pages/aw-page-aside.md +296 -0
- package/docs/components/pages/aw-page-menu-buttons.md +172 -0
- package/docs/components/pages/aw-page-modal.md +198 -0
- package/docs/components/pages/aw-page-single.md +253 -0
- package/docs/components/pages/aw-page.md +194 -0
- package/docs/configuration.md +493 -0
- package/docs/cookbook/advanced-patterns.md +1388 -0
- package/docs/cookbook/common-patterns.md +965 -0
- package/docs/cookbook/index.md +786 -0
- package/docs/getting-started.md +596 -0
- package/docs/guides/best-practices.md +1106 -0
- package/docs/guides/data-fetching.md +852 -0
- package/docs/guides/error-handling.md +1172 -0
- package/docs/guides/forms-guide.md +1329 -0
- package/docs/guides/mobile-subnavigation.md +359 -0
- package/docs/guides/page-patterns/aside-pages.md +1418 -0
- package/docs/guides/page-patterns/dashboard-pages.md +990 -0
- package/docs/guides/page-patterns/detail-pages.md +1493 -0
- package/docs/guides/page-patterns/list-pages.md +1094 -0
- package/docs/index.md +263 -1
- package/docs/integrations.md +870 -0
- package/docs/reference/menu.md +462 -0
- package/docs/reference/plugins.md +970 -0
- package/docs/reference/troubleshooting.md +945 -0
- package/nuxt/awes.config.js +9 -8
- package/nuxt/icons.css +26 -0
- package/nuxt/index.js +2 -2
- package/nuxt/pages/more.vue +1 -1
- package/package.json +5 -3
- package/readme.md +171 -1
- package/docs/aw-accordion-fold.md +0 -46
- package/docs/aw-address.md +0 -44
- package/docs/aw-avatar.md +0 -51
- package/docs/aw-badge.md +0 -32
- package/docs/aw-button-nav.md +0 -44
- package/docs/aw-button.md +0 -50
- package/docs/aw-calendar-days.md +0 -46
- package/docs/aw-calendar-nav.md +0 -25
- package/docs/aw-calendar-view.md +0 -12
- package/docs/aw-calendar.md +0 -59
- package/docs/aw-card.md +0 -48
- package/docs/aw-chart.md +0 -51
- package/docs/aw-checkbox.md +0 -56
- package/docs/aw-chip-select.md +0 -46
- package/docs/aw-chip.md +0 -53
- package/docs/aw-code-snippet.md +0 -18
- package/docs/aw-code.md +0 -56
- package/docs/aw-content-wrapper.md +0 -40
- package/docs/aw-context-menu.md +0 -31
- package/docs/aw-cropper.md +0 -60
- package/docs/aw-dashboard-card.md +0 -37
- package/docs/aw-dashboard-donut.md +0 -30
- package/docs/aw-dashboard-line.md +0 -20
- package/docs/aw-dashboard-progress.md +0 -33
- package/docs/aw-dashboard-section.md +0 -32
- package/docs/aw-dashboard-speed.md +0 -30
- package/docs/aw-date.md +0 -52
- package/docs/aw-dropdown-button.md +0 -31
- package/docs/aw-dropdown.md +0 -69
- package/docs/aw-fetch-data.md +0 -45
- package/docs/aw-form.md +0 -52
- package/docs/aw-grid.md +0 -48
- package/docs/aw-icon.md +0 -50
- package/docs/aw-info.md +0 -53
- package/docs/aw-input.md +0 -55
- package/docs/aw-layout-default.md +0 -30
- package/docs/aw-layout-frame-center.md +0 -29
- package/docs/aw-layout-simple.md +0 -49
- package/docs/aw-link.md +0 -54
- package/docs/aw-markdown-editor.md +0 -51
- package/docs/aw-modal.md +0 -63
- package/docs/aw-multi-block-builder.md +0 -66
- package/docs/aw-page.md +0 -36
- package/docs/aw-pagination.md +0 -54
- package/docs/aw-password.md +0 -48
- package/docs/aw-radio.md +0 -54
- package/docs/aw-search.md +0 -49
- package/docs/aw-select.md +0 -93
- package/docs/aw-slider.md +0 -40
- package/docs/aw-svg-image.md +0 -19
- package/docs/aw-switcher.md +0 -51
- package/docs/aw-tab-nav.md +0 -55
- package/docs/aw-table-builder.md +0 -58
- package/docs/aw-table-col.md +0 -33
- package/docs/aw-table-head.md +0 -28
- package/docs/aw-table-row.md +0 -33
- package/docs/aw-table.md +0 -59
- package/docs/aw-tel.md +0 -47
- package/docs/aw-textarea.md +0 -47
- package/docs/aw-timeline-builder.md +0 -50
- package/docs/aw-toggler.md +0 -41
- package/docs/aw-uploader-files.md +0 -20
- package/docs/aw-uploader.md +0 -60
- package/docs/aw-user-menu.md +0 -34
- package/docs/aw-userpic.md +0 -34
- /package/components/{3_organisms → 2_molecules}/AwTel.vue +0 -0
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
# Plugins & Utilities Reference
|
|
2
|
+
|
|
3
|
+
Complete reference for all AwesCode UI plugins and utility methods available in your application.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
AwesCode UI provides several plugins that extend Nuxt with custom functionality:
|
|
8
|
+
|
|
9
|
+
| Plugin | Purpose | Available As |
|
|
10
|
+
|--------|---------|--------------|
|
|
11
|
+
| **core** | Notifications, config access | `$notify`, `$confirm`, `$awes` |
|
|
12
|
+
| **screen** | Responsive breakpoints | `$screen` |
|
|
13
|
+
| **dayjs** | Date formatting | `$dayjs` |
|
|
14
|
+
| **router** | Router extensions | `router.pushBack`, `router.setBack` |
|
|
15
|
+
| **dark-theme** | Theme management | `$store.commit('awesIo/SET_DARK_THEME')`, `$store.getters['awesIo/isDarkTheme']` |
|
|
16
|
+
| **permissions** | CASL permissions | `$can`, `$cannot` |
|
|
17
|
+
|
|
18
|
+
All plugins are automatically registered by the `@awes-io/ui` Nuxt module.
|
|
19
|
+
|
|
20
|
+
## $notify
|
|
21
|
+
|
|
22
|
+
Display toast notifications to users.
|
|
23
|
+
|
|
24
|
+
### Basic Usage
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
// Success notification
|
|
28
|
+
this.$notify({
|
|
29
|
+
title: 'Customer saved successfully',
|
|
30
|
+
type: 'success'
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Error notification
|
|
34
|
+
this.$notify({
|
|
35
|
+
title: 'Failed to load data',
|
|
36
|
+
type: 'error'
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// Warning notification
|
|
40
|
+
this.$notify({
|
|
41
|
+
title: 'Data may be outdated',
|
|
42
|
+
type: 'warning'
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Info notification
|
|
46
|
+
this.$notify({
|
|
47
|
+
title: 'Processing request...',
|
|
48
|
+
type: 'info'
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Notification Types
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
// Success (green)
|
|
56
|
+
this.$notify({
|
|
57
|
+
title: 'Operation completed',
|
|
58
|
+
type: 'success'
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Error (red)
|
|
62
|
+
this.$notify({
|
|
63
|
+
title: 'Something went wrong',
|
|
64
|
+
type: 'error'
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Warning (yellow/orange)
|
|
68
|
+
this.$notify({
|
|
69
|
+
title: 'Please review your input',
|
|
70
|
+
type: 'warning'
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Info (blue)
|
|
74
|
+
this.$notify({
|
|
75
|
+
title: 'Your session will expire in 5 minutes',
|
|
76
|
+
type: 'info'
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### With Duration
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
// Auto-dismiss after 5 seconds (default)
|
|
84
|
+
this.$notify({
|
|
85
|
+
title: 'Auto-dismiss notification'
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Auto-dismiss after 10 seconds
|
|
89
|
+
this.$notify({
|
|
90
|
+
title: 'Longer notification',
|
|
91
|
+
timeout: 10000
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// Never auto-dismiss (requires manual close)
|
|
95
|
+
this.$notify({
|
|
96
|
+
title: 'Important: Please read carefully',
|
|
97
|
+
timeout: 0
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### With Title
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
this.$notify({
|
|
105
|
+
title: 'Success',
|
|
106
|
+
text: 'Customer profile updated successfully',
|
|
107
|
+
type: 'success'
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
this.$notify({
|
|
111
|
+
title: 'Error',
|
|
112
|
+
text: 'Unable to connect to server',
|
|
113
|
+
type: 'error'
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Common Patterns
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// After successful save
|
|
121
|
+
async save() {
|
|
122
|
+
try {
|
|
123
|
+
await this.customer.save()
|
|
124
|
+
|
|
125
|
+
this.$notify({
|
|
126
|
+
title: 'Customer saved successfully',
|
|
127
|
+
type: 'success'
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
this.$router.push('/customers')
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.$notify({
|
|
133
|
+
title: 'Failed to save customer',
|
|
134
|
+
type: 'error'
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// After successful delete
|
|
140
|
+
async delete() {
|
|
141
|
+
await this.$axios.delete(`/api/customers/${id}`)
|
|
142
|
+
|
|
143
|
+
this.$notify({
|
|
144
|
+
title: 'Customer deleted',
|
|
145
|
+
type: 'success'
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Network error
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (!error.response) {
|
|
152
|
+
this.$notify({
|
|
153
|
+
title: 'Network error. Please check your connection.',
|
|
154
|
+
type: 'error'
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Bulk action
|
|
160
|
+
this.$notify({
|
|
161
|
+
title: `${count} customers updated`,
|
|
162
|
+
type: 'success'
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## $confirm
|
|
167
|
+
|
|
168
|
+
Show confirmation dialogs for destructive actions.
|
|
169
|
+
|
|
170
|
+
### Basic Usage
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
const confirmed = await this.$confirm({
|
|
174
|
+
title: 'Delete Customer',
|
|
175
|
+
message: 'Are you sure you want to delete this customer?'
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
if (confirmed) {
|
|
179
|
+
// User clicked "Confirm"
|
|
180
|
+
await this.deleteCustomer()
|
|
181
|
+
} else {
|
|
182
|
+
// User clicked "Cancel" or closed dialog
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### With Custom Button Text
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
const confirmed = await this.$confirm({
|
|
190
|
+
title: 'Permanent Delete',
|
|
191
|
+
message: 'This will permanently delete all data. This action cannot be undone.',
|
|
192
|
+
confirmText: 'Yes, Delete Everything',
|
|
193
|
+
cancelText: 'No, Keep It'
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Delete Pattern
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
async deleteCustomer(customer) {
|
|
201
|
+
const confirmed = await this.$confirm({
|
|
202
|
+
title: 'Delete Customer',
|
|
203
|
+
message: `Are you sure you want to delete ${customer.name}?`
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
if (!confirmed) {
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
await this.$axios.delete(`/api/customers/${customer.id}`)
|
|
212
|
+
|
|
213
|
+
this.$notify({
|
|
214
|
+
title: 'Customer deleted',
|
|
215
|
+
type: 'success'
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
await this.customers.fetch()
|
|
219
|
+
} catch (error) {
|
|
220
|
+
this.$notify({
|
|
221
|
+
title: 'Failed to delete customer',
|
|
222
|
+
type: 'error'
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Discard Changes Pattern
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
async leave() {
|
|
232
|
+
if (this.hasUnsavedChanges) {
|
|
233
|
+
const confirmed = await this.$confirm({
|
|
234
|
+
title: 'Unsaved Changes',
|
|
235
|
+
message: 'You have unsaved changes. Are you sure you want to leave?',
|
|
236
|
+
confirmText: 'Leave',
|
|
237
|
+
cancelText: 'Stay'
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
if (!confirmed) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.$router.push('/customers')
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### With Navigation Guard
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
export default {
|
|
253
|
+
beforeRouteLeave(to, from, next) {
|
|
254
|
+
if (this.hasUnsavedChanges) {
|
|
255
|
+
this.$confirm({
|
|
256
|
+
title: 'Unsaved Changes',
|
|
257
|
+
message: 'Are you sure you want to leave?'
|
|
258
|
+
}).then(confirmed => {
|
|
259
|
+
if (confirmed) {
|
|
260
|
+
next()
|
|
261
|
+
} else {
|
|
262
|
+
next(false)
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
} else {
|
|
266
|
+
next()
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## $screen
|
|
273
|
+
|
|
274
|
+
Reactive responsive breakpoints.
|
|
275
|
+
|
|
276
|
+
### Breakpoint Values
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
// Breakpoints (following Tailwind defaults)
|
|
280
|
+
$screen.sm // >= 640px
|
|
281
|
+
$screen.md // >= 768px
|
|
282
|
+
$screen.lg // >= 1024px
|
|
283
|
+
$screen.xl // >= 1280px
|
|
284
|
+
$screen.xxl // >= 1536px
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Usage in Templates
|
|
288
|
+
|
|
289
|
+
```markup
|
|
290
|
+
<template>
|
|
291
|
+
<div>
|
|
292
|
+
<!-- Mobile only -->
|
|
293
|
+
<div v-if="!$screen.md">
|
|
294
|
+
Mobile menu
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<!-- Desktop only -->
|
|
298
|
+
<div v-if="$screen.md">
|
|
299
|
+
Desktop menu
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<!-- Responsive columns -->
|
|
303
|
+
<AwGrid :col="$screen.md ? 2 : 1">
|
|
304
|
+
<div>Column 1</div>
|
|
305
|
+
<div>Column 2</div>
|
|
306
|
+
</AwGrid>
|
|
307
|
+
|
|
308
|
+
<!-- Conditional component -->
|
|
309
|
+
<AwTable v-if="$screen.lg" :collection="items" />
|
|
310
|
+
<AwCard v-else v-for="item in items" :key="item.id">
|
|
311
|
+
{{ item.name }}
|
|
312
|
+
</AwCard>
|
|
313
|
+
</div>
|
|
314
|
+
</template>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Usage in Methods
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
export default {
|
|
321
|
+
methods: {
|
|
322
|
+
openSidebar() {
|
|
323
|
+
// On mobile, open as modal
|
|
324
|
+
if (!this.$screen.md) {
|
|
325
|
+
this.showMobileMenu = true
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
getTableColumns() {
|
|
330
|
+
// Fewer columns on mobile
|
|
331
|
+
if (this.$screen.sm) {
|
|
332
|
+
return ['name', 'email', 'phone', 'created_at']
|
|
333
|
+
}
|
|
334
|
+
return ['name', 'email']
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Usage in Computed
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
export default {
|
|
344
|
+
computed: {
|
|
345
|
+
isMobile() {
|
|
346
|
+
return !this.$screen.md
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
columns() {
|
|
350
|
+
if (this.$screen.xl) {
|
|
351
|
+
return 4
|
|
352
|
+
}
|
|
353
|
+
if (this.$screen.lg) {
|
|
354
|
+
return 3
|
|
355
|
+
}
|
|
356
|
+
if (this.$screen.md) {
|
|
357
|
+
return 2
|
|
358
|
+
}
|
|
359
|
+
return 1
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Reactive Updates
|
|
366
|
+
|
|
367
|
+
`$screen` is reactive - components automatically update when breakpoints change:
|
|
368
|
+
|
|
369
|
+
```markup
|
|
370
|
+
<template>
|
|
371
|
+
<div>
|
|
372
|
+
<!-- Automatically updates on resize -->
|
|
373
|
+
<p>Current breakpoint: {{ currentBreakpoint }}</p>
|
|
374
|
+
</div>
|
|
375
|
+
</template>
|
|
376
|
+
|
|
377
|
+
<script>
|
|
378
|
+
export default {
|
|
379
|
+
computed: {
|
|
380
|
+
currentBreakpoint() {
|
|
381
|
+
if (this.$screen.xxl) return 'xxl'
|
|
382
|
+
if (this.$screen.xl) return 'xl'
|
|
383
|
+
if (this.$screen.lg) return 'lg'
|
|
384
|
+
if (this.$screen.md) return 'md'
|
|
385
|
+
if (this.$screen.sm) return 'sm'
|
|
386
|
+
return 'xs'
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
</script>
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## $dayjs
|
|
394
|
+
|
|
395
|
+
Date formatting and manipulation using Day.js library.
|
|
396
|
+
|
|
397
|
+
**⚠️ CRITICAL: Always use `$dayjs`, never use native `Date` constructor**
|
|
398
|
+
|
|
399
|
+
The framework uses Day.js for all date operations. Using native JavaScript `Date` constructor can cause timezone issues, inconsistent formatting, and compatibility problems. Always use `$dayjs` (in templates) or `this.$dayjs` (in methods) instead of `new Date()`.
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
// ❌ BAD - Never use native Date
|
|
403
|
+
const date = new Date(value)
|
|
404
|
+
date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
|
|
405
|
+
|
|
406
|
+
// ✅ GOOD - Always use $dayjs
|
|
407
|
+
this.$dayjs(value).format('MMM D, YYYY')
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### IMPORTANT: Template vs Method Usage
|
|
411
|
+
|
|
412
|
+
```markup
|
|
413
|
+
<template>
|
|
414
|
+
<!-- ✅ GOOD: In templates, use $dayjs WITHOUT this -->
|
|
415
|
+
{{ $dayjs(date).format('ll') }}
|
|
416
|
+
</template>
|
|
417
|
+
|
|
418
|
+
<script>
|
|
419
|
+
export default {
|
|
420
|
+
methods: {
|
|
421
|
+
formatDate(date) {
|
|
422
|
+
// ✅ GOOD: In methods, use this.$dayjs WITH this
|
|
423
|
+
return this.$dayjs(date).format('ll')
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
</script>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Common Date Formats
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
const date = '2024-01-15'
|
|
434
|
+
|
|
435
|
+
// Short date: Jan 15, 2024
|
|
436
|
+
this.$dayjs(date).format('ll')
|
|
437
|
+
|
|
438
|
+
// Long date: January 15, 2024
|
|
439
|
+
this.$dayjs(date).format('LL')
|
|
440
|
+
|
|
441
|
+
// Short date + time: Jan 15, 2024 2:30 PM
|
|
442
|
+
this.$dayjs(date).format('lll')
|
|
443
|
+
|
|
444
|
+
// Long date + time: January 15, 2024 2:30 PM
|
|
445
|
+
this.$dayjs(date).format('LLL')
|
|
446
|
+
|
|
447
|
+
// Full: Monday, January 15, 2024 2:30 PM
|
|
448
|
+
this.$dayjs(date).format('LLLL')
|
|
449
|
+
|
|
450
|
+
// Month and year: January 2024
|
|
451
|
+
this.$dayjs(date).format('MMMM YYYY')
|
|
452
|
+
|
|
453
|
+
// ISO format: 2024-01-15T14:30:00Z
|
|
454
|
+
this.$dayjs(date).toISOString()
|
|
455
|
+
|
|
456
|
+
// Relative time: 2 hours ago
|
|
457
|
+
this.$dayjs(date).fromNow()
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Template Usage
|
|
461
|
+
|
|
462
|
+
```markup
|
|
463
|
+
<template>
|
|
464
|
+
<div>
|
|
465
|
+
<!-- Short date -->
|
|
466
|
+
<p>{{ $dayjs(customer.created_at).format('ll') }}</p>
|
|
467
|
+
|
|
468
|
+
<!-- Month and year -->
|
|
469
|
+
<p>{{ $dayjs(order.date).format('MMMM YYYY') }}</p>
|
|
470
|
+
|
|
471
|
+
<!-- Relative time -->
|
|
472
|
+
<p>Updated {{ $dayjs(item.updated_at).fromNow() }}</p>
|
|
473
|
+
|
|
474
|
+
<!-- Custom format -->
|
|
475
|
+
<p>{{ $dayjs(event.date).format('MMM D, YYYY [at] h:mm A') }}</p>
|
|
476
|
+
</div>
|
|
477
|
+
</template>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Common Patterns
|
|
481
|
+
|
|
482
|
+
```javascript
|
|
483
|
+
// Display created date
|
|
484
|
+
computed: {
|
|
485
|
+
createdDate() {
|
|
486
|
+
return this.$dayjs(this.customer.created_at).format('ll')
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Display relative time
|
|
491
|
+
computed: {
|
|
492
|
+
lastUpdated() {
|
|
493
|
+
return this.$dayjs(this.item.updated_at).fromNow()
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Filter by date range
|
|
498
|
+
methods: {
|
|
499
|
+
filterByMonth(month, year) {
|
|
500
|
+
const start = this.$dayjs(`${year}-${month}-01`).startOf('month')
|
|
501
|
+
const end = this.$dayjs(`${year}-${month}-01`).endOf('month')
|
|
502
|
+
|
|
503
|
+
return this.items.filter(item => {
|
|
504
|
+
const date = this.$dayjs(item.date)
|
|
505
|
+
return date.isAfter(start) && date.isBefore(end)
|
|
506
|
+
})
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Sort by date
|
|
511
|
+
methods: {
|
|
512
|
+
sortByDate() {
|
|
513
|
+
return this.items.sort((a, b) => {
|
|
514
|
+
return this.$dayjs(a.date).diff(this.$dayjs(b.date))
|
|
515
|
+
})
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Date Manipulation
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
// Add time
|
|
524
|
+
this.$dayjs().add(7, 'day') // 7 days from now
|
|
525
|
+
this.$dayjs().add(1, 'month') // 1 month from now
|
|
526
|
+
this.$dayjs().add(2, 'year') // 2 years from now
|
|
527
|
+
|
|
528
|
+
// Subtract time
|
|
529
|
+
this.$dayjs().subtract(3, 'day') // 3 days ago
|
|
530
|
+
this.$dayjs().subtract(1, 'week') // 1 week ago
|
|
531
|
+
|
|
532
|
+
// Start/end of period
|
|
533
|
+
this.$dayjs().startOf('month') // First day of month
|
|
534
|
+
this.$dayjs().endOf('month') // Last day of month
|
|
535
|
+
this.$dayjs().startOf('week') // Start of week (Sunday)
|
|
536
|
+
|
|
537
|
+
// Comparison
|
|
538
|
+
const date1 = this.$dayjs('2024-01-15')
|
|
539
|
+
const date2 = this.$dayjs('2024-02-20')
|
|
540
|
+
|
|
541
|
+
date1.isBefore(date2) // true
|
|
542
|
+
date1.isAfter(date2) // false
|
|
543
|
+
date1.isSame(date2) // false
|
|
544
|
+
|
|
545
|
+
// Difference
|
|
546
|
+
date2.diff(date1, 'day') // 36 days
|
|
547
|
+
date2.diff(date1, 'month') // 1 month
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## router.pushBack / router.setBack
|
|
551
|
+
|
|
552
|
+
Navigate back to a specific route.
|
|
553
|
+
|
|
554
|
+
### Basic Usage
|
|
555
|
+
|
|
556
|
+
```javascript
|
|
557
|
+
// Set where "back" should go
|
|
558
|
+
this.$router.setBack('/customers')
|
|
559
|
+
|
|
560
|
+
// Navigate back
|
|
561
|
+
this.$router.pushBack()
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Common Pattern
|
|
565
|
+
|
|
566
|
+
```javascript
|
|
567
|
+
// On list page - set back route
|
|
568
|
+
mounted() {
|
|
569
|
+
this.$router.setBack('/customers')
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// On detail page - go back
|
|
573
|
+
methods: {
|
|
574
|
+
cancel() {
|
|
575
|
+
this.$router.pushBack()
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### With Fallback
|
|
581
|
+
|
|
582
|
+
```javascript
|
|
583
|
+
// Go back, or fallback to /dashboard
|
|
584
|
+
this.$router.pushBack('/dashboard')
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### Complete Example
|
|
588
|
+
|
|
589
|
+
```markup
|
|
590
|
+
<!-- List Page -->
|
|
591
|
+
<script>
|
|
592
|
+
export default {
|
|
593
|
+
mounted() {
|
|
594
|
+
// Set back route for detail pages
|
|
595
|
+
this.$router.setBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
596
|
+
},
|
|
597
|
+
|
|
598
|
+
methods: {
|
|
599
|
+
viewCustomer(customer) {
|
|
600
|
+
this.$router.push(`/shops/${this.$route.params.shop_uuid}/customers/${customer.id}`)
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
</script>
|
|
605
|
+
|
|
606
|
+
<!-- Detail Page -->
|
|
607
|
+
<script>
|
|
608
|
+
export default {
|
|
609
|
+
methods: {
|
|
610
|
+
async save() {
|
|
611
|
+
await this.customer.save()
|
|
612
|
+
|
|
613
|
+
this.$notify({
|
|
614
|
+
title: 'Customer saved',
|
|
615
|
+
type: 'success'
|
|
616
|
+
})
|
|
617
|
+
|
|
618
|
+
// Go back to list
|
|
619
|
+
this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
620
|
+
},
|
|
621
|
+
|
|
622
|
+
cancel() {
|
|
623
|
+
// Go back without saving
|
|
624
|
+
this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
</script>
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
## $awes
|
|
632
|
+
|
|
633
|
+
Access AwesCode UI configuration and utilities.
|
|
634
|
+
|
|
635
|
+
### Configuration Access
|
|
636
|
+
|
|
637
|
+
```javascript
|
|
638
|
+
// Get component config
|
|
639
|
+
const buttonConfig = this.$awes.config.AwButton
|
|
640
|
+
|
|
641
|
+
// Get global config
|
|
642
|
+
const apiUrl = this.$awes.config.apiUrl
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Usage
|
|
646
|
+
|
|
647
|
+
```javascript
|
|
648
|
+
export default {
|
|
649
|
+
computed: {
|
|
650
|
+
defaultButtonSize() {
|
|
651
|
+
return this.$awes.config.AwButton?.size || 'md'
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## $can / $cannot (CASL Permissions)
|
|
658
|
+
|
|
659
|
+
Check user permissions (if CASL is configured).
|
|
660
|
+
|
|
661
|
+
### Basic Usage
|
|
662
|
+
|
|
663
|
+
```markup
|
|
664
|
+
<template>
|
|
665
|
+
<div>
|
|
666
|
+
<!-- Show button only if user can create -->
|
|
667
|
+
<AwButton v-if="$can('create', 'Customer')">
|
|
668
|
+
Add Customer
|
|
669
|
+
</AwButton>
|
|
670
|
+
|
|
671
|
+
<!-- Show button only if user can edit -->
|
|
672
|
+
<AwButton v-if="$can('update', customer)">
|
|
673
|
+
Edit
|
|
674
|
+
</AwButton>
|
|
675
|
+
|
|
676
|
+
<!-- Show button only if user can delete -->
|
|
677
|
+
<AwButton v-if="$can('delete', customer)">
|
|
678
|
+
Delete
|
|
679
|
+
</AwButton>
|
|
680
|
+
|
|
681
|
+
<!-- Inverse check -->
|
|
682
|
+
<p v-if="$cannot('view', 'Reports')">
|
|
683
|
+
You don't have access to reports
|
|
684
|
+
</p>
|
|
685
|
+
</div>
|
|
686
|
+
</template>
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
### In Methods
|
|
690
|
+
|
|
691
|
+
```javascript
|
|
692
|
+
export default {
|
|
693
|
+
methods: {
|
|
694
|
+
async deleteCustomer(customer) {
|
|
695
|
+
// Check permission
|
|
696
|
+
if (!this.$can('delete', customer)) {
|
|
697
|
+
this.$notify({
|
|
698
|
+
title: 'You do not have permission to delete this customer',
|
|
699
|
+
type: 'error'
|
|
700
|
+
})
|
|
701
|
+
return
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Proceed with delete
|
|
705
|
+
await this.$axios.delete(`/api/customers/${customer.id}`)
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
## Dark Theme Management
|
|
712
|
+
|
|
713
|
+
Toggle between light and dark themes using Vuex store.
|
|
714
|
+
|
|
715
|
+
### Basic Usage
|
|
716
|
+
|
|
717
|
+
```markup
|
|
718
|
+
<template>
|
|
719
|
+
<AwButton @click="toggleTheme">
|
|
720
|
+
Toggle Theme
|
|
721
|
+
</AwButton>
|
|
722
|
+
</template>
|
|
723
|
+
|
|
724
|
+
<script>
|
|
725
|
+
export default {
|
|
726
|
+
methods: {
|
|
727
|
+
toggleTheme() {
|
|
728
|
+
const currentTheme = this.$store.getters['awesIo/isDarkTheme']
|
|
729
|
+
this.$store.commit('awesIo/SET_DARK_THEME', !currentTheme)
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
</script>
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Using v-model with Switcher
|
|
737
|
+
|
|
738
|
+
```markup
|
|
739
|
+
<template>
|
|
740
|
+
<AwSwitcher v-model="isDarkTheme" size="lg" />
|
|
741
|
+
</template>
|
|
742
|
+
|
|
743
|
+
<script>
|
|
744
|
+
export default {
|
|
745
|
+
computed: {
|
|
746
|
+
isDarkTheme: {
|
|
747
|
+
get() {
|
|
748
|
+
return this.$store.getters['awesIo/isDarkTheme']
|
|
749
|
+
},
|
|
750
|
+
set(val) {
|
|
751
|
+
this.$store.commit('awesIo/SET_DARK_THEME', val)
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
</script>
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
### With Icon Button
|
|
760
|
+
|
|
761
|
+
```markup
|
|
762
|
+
<template>
|
|
763
|
+
<AwButton @click="toggleTheme">
|
|
764
|
+
<AwIcon :name="isDarkTheme ? 'sun' : 'moon'" />
|
|
765
|
+
{{ isDarkTheme ? 'Light Mode' : 'Dark Mode' }}
|
|
766
|
+
</AwButton>
|
|
767
|
+
</template>
|
|
768
|
+
|
|
769
|
+
<script>
|
|
770
|
+
export default {
|
|
771
|
+
computed: {
|
|
772
|
+
isDarkTheme() {
|
|
773
|
+
return this.$store.getters['awesIo/isDarkTheme']
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
|
|
777
|
+
methods: {
|
|
778
|
+
toggleTheme() {
|
|
779
|
+
this.$store.commit('awesIo/SET_DARK_THEME', !this.isDarkTheme)
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
</script>
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
## Complete Examples
|
|
787
|
+
|
|
788
|
+
### Form with Full Error Handling
|
|
789
|
+
|
|
790
|
+
```markup
|
|
791
|
+
<template>
|
|
792
|
+
<AwPageSingle
|
|
793
|
+
hide-menu
|
|
794
|
+
:title="customer.isNew() ? 'New Customer' : 'Edit Customer'"
|
|
795
|
+
>
|
|
796
|
+
<AwCard title="Customer Information">
|
|
797
|
+
<AwInput
|
|
798
|
+
v-model="customer.name"
|
|
799
|
+
:error="customer.errors.name"
|
|
800
|
+
label="Name"
|
|
801
|
+
/>
|
|
802
|
+
|
|
803
|
+
<AwInput
|
|
804
|
+
v-model="customer.email"
|
|
805
|
+
:error="customer.errors.email"
|
|
806
|
+
label="Email"
|
|
807
|
+
type="email"
|
|
808
|
+
/>
|
|
809
|
+
|
|
810
|
+
<AwDate
|
|
811
|
+
v-model="customer.birthday"
|
|
812
|
+
:error="customer.errors.birthday"
|
|
813
|
+
label="Birthday"
|
|
814
|
+
/>
|
|
815
|
+
|
|
816
|
+
<!-- Display formatted date -->
|
|
817
|
+
<p v-if="customer.birthday">
|
|
818
|
+
Birthday: {{ $dayjs(customer.birthday).format('LL') }}
|
|
819
|
+
</p>
|
|
820
|
+
</AwCard>
|
|
821
|
+
|
|
822
|
+
<template #buttons>
|
|
823
|
+
<AwButton
|
|
824
|
+
:loading="saving"
|
|
825
|
+
color="accent"
|
|
826
|
+
@click="save"
|
|
827
|
+
>
|
|
828
|
+
Save
|
|
829
|
+
</AwButton>
|
|
830
|
+
|
|
831
|
+
<AwButton @click="cancel">
|
|
832
|
+
Cancel
|
|
833
|
+
</AwButton>
|
|
834
|
+
</template>
|
|
835
|
+
</AwPageSingle>
|
|
836
|
+
</template>
|
|
837
|
+
|
|
838
|
+
<script>
|
|
839
|
+
import Customer from '~/models/Customer'
|
|
840
|
+
|
|
841
|
+
export default {
|
|
842
|
+
data() {
|
|
843
|
+
return {
|
|
844
|
+
customer: new Customer(
|
|
845
|
+
{},
|
|
846
|
+
null,
|
|
847
|
+
{ shop_uuid: this.$route.params.shop_uuid }
|
|
848
|
+
),
|
|
849
|
+
saving: false
|
|
850
|
+
}
|
|
851
|
+
},
|
|
852
|
+
|
|
853
|
+
methods: {
|
|
854
|
+
async save() {
|
|
855
|
+
this.saving = true
|
|
856
|
+
|
|
857
|
+
try {
|
|
858
|
+
await this.customer.save()
|
|
859
|
+
|
|
860
|
+
if (Object.keys(this.customer.errors).length > 0) {
|
|
861
|
+
this.$notify({
|
|
862
|
+
title: 'Please fix validation errors',
|
|
863
|
+
type: 'error'
|
|
864
|
+
})
|
|
865
|
+
return
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
this.$notify({
|
|
869
|
+
title: 'Customer saved successfully',
|
|
870
|
+
type: 'success'
|
|
871
|
+
})
|
|
872
|
+
|
|
873
|
+
this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
874
|
+
} catch (error) {
|
|
875
|
+
this.$notify({
|
|
876
|
+
title: 'Failed to save customer',
|
|
877
|
+
type: 'error'
|
|
878
|
+
})
|
|
879
|
+
} finally {
|
|
880
|
+
this.saving = false
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
cancel() {
|
|
885
|
+
this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
</script>
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### Responsive Table
|
|
893
|
+
|
|
894
|
+
```markup
|
|
895
|
+
<template>
|
|
896
|
+
<AwPage title="Customers">
|
|
897
|
+
<template #buttons>
|
|
898
|
+
<AwButton
|
|
899
|
+
v-if="$can('create', 'Customer')"
|
|
900
|
+
:href="`/shops/${$route.params.shop_uuid}/customers/new`"
|
|
901
|
+
color="accent"
|
|
902
|
+
>
|
|
903
|
+
Add Customer
|
|
904
|
+
</AwButton>
|
|
905
|
+
</template>
|
|
906
|
+
|
|
907
|
+
<!-- Desktop table -->
|
|
908
|
+
<AwTableBuilder
|
|
909
|
+
v-if="$screen.md"
|
|
910
|
+
:collection="customers"
|
|
911
|
+
@click:row="viewCustomer"
|
|
912
|
+
>
|
|
913
|
+
<AwTableCol field="name" title="Name" />
|
|
914
|
+
<AwTableCol field="email" title="Email" />
|
|
915
|
+
<AwTableCol field="phone" title="Phone" />
|
|
916
|
+
<AwTableCol field="created_at" title="Created">
|
|
917
|
+
<template #default="{ cell }">
|
|
918
|
+
{{ $dayjs(cell).format('ll') }}
|
|
919
|
+
</template>
|
|
920
|
+
</AwTableCol>
|
|
921
|
+
</AwTableBuilder>
|
|
922
|
+
|
|
923
|
+
<!-- Mobile cards -->
|
|
924
|
+
<div v-else>
|
|
925
|
+
<AwCard
|
|
926
|
+
v-for="customer in customers.models"
|
|
927
|
+
:key="customer.id"
|
|
928
|
+
class="mb-4"
|
|
929
|
+
@click="viewCustomer(customer)"
|
|
930
|
+
>
|
|
931
|
+
<h3>{{ customer.name }}</h3>
|
|
932
|
+
<p>{{ customer.email }}</p>
|
|
933
|
+
<p class="text-sm text-gray-500">
|
|
934
|
+
Created {{ $dayjs(customer.created_at).fromNow() }}
|
|
935
|
+
</p>
|
|
936
|
+
</AwCard>
|
|
937
|
+
</div>
|
|
938
|
+
</AwPage>
|
|
939
|
+
</template>
|
|
940
|
+
|
|
941
|
+
<script>
|
|
942
|
+
import Customers from '~/collections/Customers'
|
|
943
|
+
|
|
944
|
+
export default {
|
|
945
|
+
data() {
|
|
946
|
+
return {
|
|
947
|
+
customers: new Customers([], {
|
|
948
|
+
shop_uuid: this.$route.params.shop_uuid
|
|
949
|
+
})
|
|
950
|
+
}
|
|
951
|
+
},
|
|
952
|
+
|
|
953
|
+
mounted() {
|
|
954
|
+
this.$router.setBack(`/shops/${this.$route.params.shop_uuid}/customers`)
|
|
955
|
+
},
|
|
956
|
+
|
|
957
|
+
methods: {
|
|
958
|
+
viewCustomer(customer) {
|
|
959
|
+
this.$router.push(`/shops/${this.$route.params.shop_uuid}/customers/${customer.id}`)
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
</script>
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
## See Also
|
|
967
|
+
|
|
968
|
+
- [Error Handling Guide](../guides/error-handling.md) - Using $notify and $confirm
|
|
969
|
+
- [Data Fetching Guide](../guides/data-fetching.md) - Using date formatting in templates
|
|
970
|
+
- [Best Practices Guide](../guides/best-practices.md) - Plugin usage patterns
|