@stacksjs/defaults 0.75.231 → 0.75.233
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/ai/skills/stacks-native/CATALOG.md +4 -4
- package/ai/skills/stacks-storage/SKILL.md +43 -0
- package/ai/skills/stacks-testing/SKILL.md +38 -10
- package/functions/dashboard-form.test.ts +41 -0
- package/functions/dashboard-form.ts +30 -0
- package/functions/dashboard-list.test.ts +228 -0
- package/functions/dashboard-list.ts +257 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/project/storage/framework/types/browser-composables.d.ts +56 -0
- package/resources/components/Dashboard/Commerce/CommerceCategoriesDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceCategoryDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceCouponDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceCouponsDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceCustomerDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceCustomersDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceGiftCardDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceGiftCardsDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceManufacturerDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceOrderDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceOrdersDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceProductDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceProductsDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/CommerceReviewEditDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceTaxDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceUnitDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/CommerceVariantDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/Delivery/CouriersDashboard.stx +45 -92
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesDashboard.stx +46 -92
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysDashboard.stx +46 -92
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesDashboard.stx +44 -90
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesDashboard.stx +45 -91
- package/resources/components/Dashboard/Commerce/PrintDeviceDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/PrintDevicesDashboard.stx +2 -7
- package/resources/components/Dashboard/Commerce/ProductWaitlistEntryDialog.stx +2 -4
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistEntryDialog.stx +2 -4
- package/resources/components/Dashboard/Marketing/AbandonedCartsDashboard.stx +2 -9
- package/resources/components/Dashboard/Marketing/CampaignsDashboard.stx +2 -9
- package/resources/components/Dashboard/Marketing/MarketingListsDashboard.stx +2 -9
- package/resources/components/Dashboard/Marketing/SocialPostsDashboard.stx +2 -9
- package/resources/plugins/preloader.ts +9 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { Signal } from '@stacksjs/stx'
|
|
2
|
+
import { state } from '@stacksjs/stx'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared pieces of the dashboard's list screens.
|
|
6
|
+
*
|
|
7
|
+
* Seventeen list dashboards each wrote their own `previousPage` and
|
|
8
|
+
* `nextPage` (stacksjs/stacks#2918), in four different styles. Twelve of them
|
|
9
|
+
* mean the same thing - move a page number, keep it between one and the last
|
|
10
|
+
* page - and this is that, once.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** The shape `state()` returns, narrowed to what paging needs. */
|
|
14
|
+
interface PageSignal {
|
|
15
|
+
(): number
|
|
16
|
+
set: (value: number) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PageControls {
|
|
20
|
+
/** Back one page, never past the first. */
|
|
21
|
+
previousPage: () => void
|
|
22
|
+
/** Forward one page, never past the last. */
|
|
23
|
+
nextPage: () => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Previous and next for a page number bounded by a last page.
|
|
28
|
+
*
|
|
29
|
+
* `lastPage` is an accessor rather than a number because every call site
|
|
30
|
+
* derives it, and reading it at click time is what keeps the clamp correct
|
|
31
|
+
* when a filter shrinks the result set under the reader's feet.
|
|
32
|
+
*
|
|
33
|
+
* Clamps rather than guards. The twelve call sites split between
|
|
34
|
+
* `page.set(Math.max(1, page() - 1))` and `if (page() > 1) page.set(page() - 1)`,
|
|
35
|
+
* which do the same thing from a user's point of view; clamping is the one
|
|
36
|
+
* that stays correct if a page number is ever set out of range by something
|
|
37
|
+
* other than these two functions.
|
|
38
|
+
*
|
|
39
|
+
* Not for the dashboards that page server-side. `Jobs/JobHistory` reloads
|
|
40
|
+
* inside its `nextPage`, and a navigation that triggers a fetch is a
|
|
41
|
+
* different thing wearing the same name.
|
|
42
|
+
*/
|
|
43
|
+
export function pageControls(page: PageSignal, lastPage: () => number): PageControls {
|
|
44
|
+
return {
|
|
45
|
+
previousPage: () => page.set(Math.max(1, page() - 1)),
|
|
46
|
+
nextPage: () => page.set(Math.min(Math.max(1, lastPage()), page() + 1)),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** How a list screen decides what the current search matches. */
|
|
51
|
+
export interface RecordsDashboardOptions<T> {
|
|
52
|
+
/**
|
|
53
|
+
* Rows matching `query`, which arrives trimmed and lowercased.
|
|
54
|
+
*
|
|
55
|
+
* The caller's, because the fields worth searching are the only part of a
|
|
56
|
+
* list dashboard that is genuinely about its own records.
|
|
57
|
+
*/
|
|
58
|
+
filter: (records: T[], query: string) => T[]
|
|
59
|
+
/** Rows per page. Default 10, which is what all five callers used. */
|
|
60
|
+
perPage?: number
|
|
61
|
+
/**
|
|
62
|
+
* Whether two rows are the same row. Defaults to matching `id`, which is
|
|
63
|
+
* what every current caller means.
|
|
64
|
+
*/
|
|
65
|
+
sameRecord?: (a: T, b: T) => boolean
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface RecordsDashboard<T> {
|
|
69
|
+
records: Signal<T[]>
|
|
70
|
+
loading: Signal<boolean>
|
|
71
|
+
loadError: Signal<string>
|
|
72
|
+
search: Signal<string>
|
|
73
|
+
page: Signal<number>
|
|
74
|
+
perPage: Signal<number>
|
|
75
|
+
editorOpen: Signal<boolean>
|
|
76
|
+
editorMode: Signal<'create' | 'edit'>
|
|
77
|
+
editing: Signal<T | null>
|
|
78
|
+
saving: Signal<boolean>
|
|
79
|
+
editorError: Signal<string>
|
|
80
|
+
deleting: Signal<T | null>
|
|
81
|
+
deleteBusy: Signal<boolean>
|
|
82
|
+
deleteError: Signal<string>
|
|
83
|
+
filteredRecords: () => T[]
|
|
84
|
+
paginatedRecords: () => T[]
|
|
85
|
+
pageCount: () => number
|
|
86
|
+
previousPage: () => void
|
|
87
|
+
nextPage: () => void
|
|
88
|
+
/**
|
|
89
|
+
* Jump to a page, clamped into range.
|
|
90
|
+
*
|
|
91
|
+
* The five callers each wrote a bare `page.set(value)` and trusted the
|
|
92
|
+
* pagination component to emit only pages that exist. Clamping costs
|
|
93
|
+
* nothing when that is true and keeps the list rendering when it is not.
|
|
94
|
+
*/
|
|
95
|
+
goToPage: (value: number) => void
|
|
96
|
+
/** Set the search and return to the first page, which is the only sane page to land on. */
|
|
97
|
+
handleSearch: (value: string) => void
|
|
98
|
+
openCreate: () => void
|
|
99
|
+
openEdit: (record: T) => void
|
|
100
|
+
/** Refuses while a save is in flight, so a half-written row cannot be abandoned by accident. */
|
|
101
|
+
closeEditor: () => void
|
|
102
|
+
requestDelete: (record: T) => void
|
|
103
|
+
closeDelete: () => void
|
|
104
|
+
/**
|
|
105
|
+
* Put a saved row into the list.
|
|
106
|
+
*
|
|
107
|
+
* `replacing` is the row the editor was opened on, or null for a create.
|
|
108
|
+
* Passed rather than inferred so the behaviour matches what the five
|
|
109
|
+
* callers did: an edit replaces in place and a create appends and jumps to
|
|
110
|
+
* the page the new row landed on.
|
|
111
|
+
*/
|
|
112
|
+
upsert: (record: T, replacing: T | null) => void
|
|
113
|
+
/** Drop a row and pull the page back if that emptied the last one. */
|
|
114
|
+
remove: (record: T) => void
|
|
115
|
+
/** Pull `page` back into range after the row count changes under it. */
|
|
116
|
+
clampPage: () => void
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The state and lifecycle every list screen in the dashboard repeats.
|
|
121
|
+
*
|
|
122
|
+
* Five Delivery dashboards carried byte-identical copies of fourteen signals,
|
|
123
|
+
* `handleSearch`, `openCreate`, `openEdit`, `closeEditor`, `requestDelete`,
|
|
124
|
+
* `closeDelete`, and the page arithmetic around saving and deleting
|
|
125
|
+
* (stacksjs/stacks#2918). Five copies of an off-by-one is four chances to be
|
|
126
|
+
* right in four places and wrong in the fifth.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately not here: fetching, toasts, and the search predicate. Those
|
|
129
|
+
* differ per screen, and a composable that owned them would be a framework
|
|
130
|
+
* each caller had to fight. The caller writes its own `load`, `save` and
|
|
131
|
+
* `delete`, and calls `upsert`, `remove` and `clampPage` from inside them.
|
|
132
|
+
*/
|
|
133
|
+
export function useRecordsDashboard<T>(options: RecordsDashboardOptions<T>): RecordsDashboard<T> {
|
|
134
|
+
const sameRecord = options.sameRecord
|
|
135
|
+
?? ((a: T, b: T) => (a as { id?: unknown }).id === (b as { id?: unknown }).id)
|
|
136
|
+
|
|
137
|
+
const records = state<T[]>([])
|
|
138
|
+
const loading = state(true)
|
|
139
|
+
const loadError = state('')
|
|
140
|
+
const search = state('')
|
|
141
|
+
const page = state(1)
|
|
142
|
+
const perPage = state(options.perPage ?? 10)
|
|
143
|
+
const editorOpen = state(false)
|
|
144
|
+
const editorMode = state<'create' | 'edit'>('create')
|
|
145
|
+
const editing = state<T | null>(null)
|
|
146
|
+
const saving = state(false)
|
|
147
|
+
const editorError = state('')
|
|
148
|
+
const deleting = state<T | null>(null)
|
|
149
|
+
const deleteBusy = state(false)
|
|
150
|
+
const deleteError = state('')
|
|
151
|
+
|
|
152
|
+
const filteredRecords = (): T[] => {
|
|
153
|
+
const query = search().trim().toLowerCase()
|
|
154
|
+
return query ? options.filter(records(), query) : records()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const pageCount = (): number => Math.max(1, Math.ceil(filteredRecords().length / perPage()))
|
|
158
|
+
|
|
159
|
+
const paginatedRecords = (): T[] => {
|
|
160
|
+
const start = (page() - 1) * perPage()
|
|
161
|
+
return filteredRecords().slice(start, start + perPage())
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const clampPage = (): void => {
|
|
165
|
+
const lastPage = pageCount()
|
|
166
|
+
if (page() > lastPage)
|
|
167
|
+
page.set(lastPage)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
171
|
+
|
|
172
|
+
const goToPage = (value: number): void => {
|
|
173
|
+
page.set(Math.min(Math.max(1, Math.trunc(value) || 1), pageCount()))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
records,
|
|
178
|
+
loading,
|
|
179
|
+
loadError,
|
|
180
|
+
search,
|
|
181
|
+
page,
|
|
182
|
+
perPage,
|
|
183
|
+
editorOpen,
|
|
184
|
+
editorMode,
|
|
185
|
+
editing,
|
|
186
|
+
saving,
|
|
187
|
+
editorError,
|
|
188
|
+
deleting,
|
|
189
|
+
deleteBusy,
|
|
190
|
+
deleteError,
|
|
191
|
+
filteredRecords,
|
|
192
|
+
paginatedRecords,
|
|
193
|
+
pageCount,
|
|
194
|
+
previousPage,
|
|
195
|
+
nextPage,
|
|
196
|
+
goToPage,
|
|
197
|
+
|
|
198
|
+
handleSearch(value: string): void {
|
|
199
|
+
search.set(value)
|
|
200
|
+
page.set(1)
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
openCreate(): void {
|
|
204
|
+
editing.set(null)
|
|
205
|
+
editorMode.set('create')
|
|
206
|
+
editorError.set('')
|
|
207
|
+
editorOpen.set(true)
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
openEdit(record: T): void {
|
|
211
|
+
editing.set(record)
|
|
212
|
+
editorMode.set('edit')
|
|
213
|
+
editorError.set('')
|
|
214
|
+
editorOpen.set(true)
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
closeEditor(): void {
|
|
218
|
+
if (saving())
|
|
219
|
+
return
|
|
220
|
+
editorOpen.set(false)
|
|
221
|
+
editing.set(null)
|
|
222
|
+
editorError.set('')
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
requestDelete(record: T): void {
|
|
226
|
+
deleting.set(record)
|
|
227
|
+
deleteError.set('')
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
closeDelete(): void {
|
|
231
|
+
if (deleteBusy())
|
|
232
|
+
return
|
|
233
|
+
deleting.set(null)
|
|
234
|
+
deleteError.set('')
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
upsert(record: T, replacing: T | null): void {
|
|
238
|
+
if (replacing) {
|
|
239
|
+
records.set(records().map(existing => sameRecord(existing, replacing) ? record : existing))
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
const next = [...records(), record]
|
|
243
|
+
records.set(next)
|
|
244
|
+
// Land on the page the new row is actually on, not the last page of the
|
|
245
|
+
// filtered view: a create while a search is active would otherwise jump
|
|
246
|
+
// somewhere the row is not.
|
|
247
|
+
page.set(Math.max(1, Math.ceil(next.length / perPage())))
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
remove(record: T): void {
|
|
251
|
+
records.set(records().filter(existing => !sameRecord(existing, record)))
|
|
252
|
+
clampPage()
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
clampPage,
|
|
256
|
+
}
|
|
257
|
+
}
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.233",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.233",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@iconify-json/f7": "^1.2.2",
|
|
46
46
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
47
|
-
"@stacksjs/mobile": "0.75.
|
|
47
|
+
"@stacksjs/mobile": "0.75.233",
|
|
48
48
|
"@stacksjs/sanitizer": "^0.2.534",
|
|
49
49
|
"@xterm/addon-fit": "^0.11.0",
|
|
50
50
|
"@xterm/xterm": "^6.0.0",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Hand-written, like `request-context.d.ts` beside it, and handed to
|
|
2
|
+
// `stx typecheck` with `--lib` by the `typecheck:views` script.
|
|
3
|
+
//
|
|
4
|
+
// What a `<script client>` block can reach from stx's DEMAND-INLINE
|
|
5
|
+
// composables (stacksjs/stacks#2918 follow-up). These are not ordinary
|
|
6
|
+
// auto-imports: stx scans a client script for the names it calls and inlines
|
|
7
|
+
// the implementation of just those, so they exist at runtime without an
|
|
8
|
+
// import and are invisible to any checker that is only given the module
|
|
9
|
+
// declarations. `node_modules/@stacksjs/stx/dist/composables/*.d.ts` declares
|
|
10
|
+
// them as module exports, which is the wrong shape for a global, so nothing
|
|
11
|
+
// typed them here.
|
|
12
|
+
//
|
|
13
|
+
// That is how `MembershipCard.stx` turned `typecheck:views` red while working
|
|
14
|
+
// correctly in a browser: it calls `useMouse({ target, resetOnLeave })` and
|
|
15
|
+
// subscribes, which is exactly the demand-inlined API, while the only
|
|
16
|
+
// `useMouse` a checker could see was the unrelated no-argument one in
|
|
17
|
+
// `browser-composables.d.ts`.
|
|
18
|
+
//
|
|
19
|
+
// Mirrors `dist/composables/use-mouse.d.ts` rather than inventing a shape. If
|
|
20
|
+
// stx changes it, this drifts, and the symptom is a type error on code that
|
|
21
|
+
// runs - so correct it here against that file rather than loosening it.
|
|
22
|
+
|
|
23
|
+
export {}
|
|
24
|
+
|
|
25
|
+
declare global {
|
|
26
|
+
interface StxMouseState {
|
|
27
|
+
x: number
|
|
28
|
+
y: number
|
|
29
|
+
pageX: number
|
|
30
|
+
pageY: number
|
|
31
|
+
clientX: number
|
|
32
|
+
clientY: number
|
|
33
|
+
movementX: number
|
|
34
|
+
movementY: number
|
|
35
|
+
buttons: number
|
|
36
|
+
isPressed: boolean
|
|
37
|
+
isInside: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface StxMouseOptions {
|
|
41
|
+
target?: Window | HTMLElement | null
|
|
42
|
+
touch?: boolean
|
|
43
|
+
resetOnLeave?: boolean
|
|
44
|
+
type?: 'page' | 'client' | 'screen' | 'movement'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StxMouseRef {
|
|
48
|
+
get: () => StxMouseState
|
|
49
|
+
/** Returns its own unsubscribe, which is what callers store. */
|
|
50
|
+
subscribe: (fn: (state: StxMouseState) => void) => () => void
|
|
51
|
+
stop: () => void
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Reactive mouse or pointer position, globally or within a target. */
|
|
55
|
+
function useMouse(options?: StxMouseOptions): StxMouseRef
|
|
56
|
+
}
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
} from '../../../../app/Actions/Dashboard/Commerce/commerce-category-records'
|
|
6
6
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
7
7
|
import { pushToast } from '../../../../functions/toasts'
|
|
8
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
8
9
|
|
|
9
10
|
interface CategoryIndexResponse {
|
|
10
11
|
records: CommerceCategoryRecord[]
|
|
@@ -230,13 +231,7 @@ async function deleteCategory(): Promise<void> {
|
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
|
|
233
|
-
|
|
234
|
-
page.set(Math.max(1, page() - 1))
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function nextPage(): void {
|
|
238
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
239
|
-
}
|
|
234
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
240
235
|
|
|
241
236
|
onMount(() => {
|
|
242
237
|
void loadCategories()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { CommerceCategoryRecord } from '../../../../app/Actions/Dashboard/Commerce/commerce-category-records'
|
|
3
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
3
4
|
|
|
4
5
|
const open = useReactiveProp('open', false)
|
|
5
6
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -113,10 +114,7 @@ function submit(): void {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
function errorMessages(): string[] {
|
|
116
|
-
return
|
|
117
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
118
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
119
|
-
})
|
|
117
|
+
return formErrorMessages(errors())
|
|
120
118
|
}
|
|
121
119
|
</script>
|
|
122
120
|
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
CouponStatus,
|
|
6
6
|
} from '../../../../app/Actions/Dashboard/Commerce/coupon-records'
|
|
7
7
|
import { minorToInput, moneyInputError, moneyInputStep, parseMoneyInput } from '@stacksjs/commerce/money'
|
|
8
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
8
9
|
|
|
9
10
|
const open = useReactiveProp('open', false)
|
|
10
11
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -104,10 +105,7 @@ function submit(): void {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
function errorMessages(): string[] {
|
|
107
|
-
return
|
|
108
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
109
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
110
|
-
})
|
|
108
|
+
return formErrorMessages(errors())
|
|
111
109
|
}
|
|
112
110
|
</script>
|
|
113
111
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
9
9
|
import { pushToast } from '../../../../functions/toasts'
|
|
10
10
|
import { minorToInput } from '@stacksjs/commerce/money'
|
|
11
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
11
12
|
|
|
12
13
|
interface CouponIndexResponse {
|
|
13
14
|
records: CouponRecord[]
|
|
@@ -241,13 +242,7 @@ async function deleteCoupon(): Promise<void> {
|
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
244
|
|
|
244
|
-
|
|
245
|
-
page.set(Math.max(1, page() - 1))
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function nextPage(): void {
|
|
249
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
250
|
-
}
|
|
245
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
251
246
|
|
|
252
247
|
onMount(() => {
|
|
253
248
|
void loadCoupons()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { CommerceCustomerRecord } from '../../../../app/Actions/Dashboard/Commerce/commerce-customer-records'
|
|
3
3
|
import { minorToInput, moneyInputError, moneyInputStep, parseMoneyInput } from '@stacksjs/commerce/money'
|
|
4
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
4
5
|
|
|
5
6
|
const open = useReactiveProp('open', false)
|
|
6
7
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -72,10 +73,7 @@ function submit(): void {
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
function errorMessages(): string[] {
|
|
75
|
-
return
|
|
76
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
77
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
78
|
-
})
|
|
76
|
+
return formErrorMessages(errors())
|
|
79
77
|
}
|
|
80
78
|
</script>
|
|
81
79
|
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
7
7
|
import { pushToast } from '../../../../functions/toasts'
|
|
8
8
|
import { formatCurrency, minorToInput } from '@stacksjs/commerce/money'
|
|
9
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
9
10
|
|
|
10
11
|
interface CustomerIndexResponse {
|
|
11
12
|
records: CommerceCustomerRecord[]
|
|
@@ -243,13 +244,7 @@ async function deleteCustomer(): Promise<void> {
|
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
246
|
|
|
246
|
-
|
|
247
|
-
page.set(Math.max(1, page() - 1))
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function nextPage(): void {
|
|
251
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
252
|
-
}
|
|
247
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
253
248
|
|
|
254
249
|
onMount(() => {
|
|
255
250
|
void loadCustomers()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { GiftCardRecord, GiftCardStatus } from '../../../../app/Actions/Dashboard/Commerce/gift-card-records'
|
|
3
3
|
import { minorToInput, moneyInputError, moneyInputStep, parseMoneyInput } from '@stacksjs/commerce/money'
|
|
4
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
4
5
|
|
|
5
6
|
const open = useReactiveProp('open', false)
|
|
6
7
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -148,10 +149,7 @@ function submit(): void {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
function errorMessages(): string[] {
|
|
151
|
-
return
|
|
152
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
153
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
154
|
-
})
|
|
152
|
+
return formErrorMessages(errors())
|
|
155
153
|
}
|
|
156
154
|
</script>
|
|
157
155
|
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
8
8
|
import { pushToast } from '../../../../functions/toasts'
|
|
9
9
|
import { minorToInput } from '@stacksjs/commerce/money'
|
|
10
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
10
11
|
|
|
11
12
|
interface GiftCardIndexResponse {
|
|
12
13
|
records: GiftCardRecord[]
|
|
@@ -257,13 +258,7 @@ async function deleteGiftCard(): Promise<void> {
|
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
|
|
260
|
-
|
|
261
|
-
page.set(Math.max(1, page() - 1))
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function nextPage(): void {
|
|
265
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
266
|
-
}
|
|
261
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
267
262
|
|
|
268
263
|
onMount(() => {
|
|
269
264
|
void loadGiftCards()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { ManufacturerRecord } from '../../../../app/Actions/Dashboard/Commerce/manufacturer-records'
|
|
3
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
3
4
|
|
|
4
5
|
const open = useReactiveProp('open', false)
|
|
5
6
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -41,10 +42,7 @@ function submit(): void {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
function errorMessages(): string[] {
|
|
44
|
-
return
|
|
45
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
46
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
47
|
-
})
|
|
45
|
+
return formErrorMessages(errors())
|
|
48
46
|
}
|
|
49
47
|
</script>
|
|
50
48
|
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
OrderCustomerOption,
|
|
5
5
|
} from '../../../../app/Actions/Dashboard/Commerce/commerce-order-records'
|
|
6
6
|
import { minorToInput, moneyInputError, moneyInputStep, parseMoneyInput } from '@stacksjs/commerce/money'
|
|
7
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
7
8
|
|
|
8
9
|
const open = useReactiveProp('open', false)
|
|
9
10
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -108,10 +109,7 @@ function submit(): void {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
function errorMessages(): string[] {
|
|
111
|
-
return
|
|
112
|
-
const fieldLabel = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
113
|
-
return `${fieldLabel.charAt(0).toUpperCase()}${fieldLabel.slice(1)}: ${message}`
|
|
114
|
-
})
|
|
112
|
+
return formErrorMessages(errors())
|
|
115
113
|
}
|
|
116
114
|
</script>
|
|
117
115
|
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
8
8
|
import { pushToast } from '../../../../functions/toasts'
|
|
9
9
|
import { formatCurrency, minorToInput } from '@stacksjs/commerce/money'
|
|
10
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
10
11
|
|
|
11
12
|
interface OrderIndexResponse {
|
|
12
13
|
records: CommerceOrderRecord[]
|
|
@@ -284,13 +285,7 @@ async function deleteOrder(): Promise<void> {
|
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
|
|
287
|
-
|
|
288
|
-
page.set(Math.max(1, page() - 1))
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function nextPage(): void {
|
|
292
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
293
|
-
}
|
|
288
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
294
289
|
|
|
295
290
|
onMount(() => {
|
|
296
291
|
void loadOrders()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script client>
|
|
2
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
2
3
|
import type {
|
|
3
4
|
CommerceProductRecord,
|
|
4
5
|
ProductOption,
|
|
@@ -108,10 +109,7 @@ function submit(): void {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
function errorMessages(): string[] {
|
|
111
|
-
return
|
|
112
|
-
const fieldLabel = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
113
|
-
return `${fieldLabel.charAt(0).toUpperCase()}${fieldLabel.slice(1)}: ${message}`
|
|
114
|
-
})
|
|
112
|
+
return formErrorMessages(errors())
|
|
115
113
|
}
|
|
116
114
|
</script>
|
|
117
115
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
|
|
9
9
|
import { pushToast } from '../../../../functions/toasts'
|
|
10
10
|
import { minorToInput } from '@stacksjs/commerce/money'
|
|
11
|
+
import { pageControls } from '../../../../functions/dashboard-list'
|
|
11
12
|
|
|
12
13
|
interface ProductIndexResponse {
|
|
13
14
|
records: CommerceProductRecord[]
|
|
@@ -259,13 +260,7 @@ async function deleteProduct(): Promise<void> {
|
|
|
259
260
|
}
|
|
260
261
|
}
|
|
261
262
|
|
|
262
|
-
|
|
263
|
-
page.set(Math.max(1, page() - 1))
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function nextPage(): void {
|
|
267
|
-
page.set(Math.min(pageCount(), page() + 1))
|
|
268
|
-
}
|
|
263
|
+
const { previousPage, nextPage } = pageControls(page, pageCount)
|
|
269
264
|
|
|
270
265
|
onMount(() => {
|
|
271
266
|
void loadProducts()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { ReviewRecord } from '../../../../app/Actions/Dashboard/Commerce/review-records'
|
|
3
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
3
4
|
|
|
4
5
|
const open = useReactiveProp('open', false)
|
|
5
6
|
const review = useReactiveProp('review', null as ReviewRecord | null)
|
|
@@ -42,10 +43,7 @@ function submit(): void {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function errorMessages(): string[] {
|
|
45
|
-
return
|
|
46
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
47
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
48
|
-
})
|
|
46
|
+
return formErrorMessages(errors())
|
|
49
47
|
}
|
|
50
48
|
</script>
|
|
51
49
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { TaxRateRecord } from '../../../../app/Actions/Dashboard/Commerce/tax-rate-records'
|
|
3
|
+
import { formErrorMessages } from '../../../../functions/dashboard-form'
|
|
3
4
|
|
|
4
5
|
const open = useReactiveProp('open', false)
|
|
5
6
|
const mode = useReactiveProp('mode', 'add')
|
|
@@ -59,10 +60,7 @@ function submit(): void {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function errorMessages(): string[] {
|
|
62
|
-
return
|
|
63
|
-
const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
|
|
64
|
-
return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
|
|
65
|
-
})
|
|
63
|
+
return formErrorMessages(errors())
|
|
66
64
|
}
|
|
67
65
|
</script>
|
|
68
66
|
|